Introduction

This comprehensive training manual provides essential tips, tricks, shortcuts, and best practices for R programming across various domains. Whether you’re a beginner or intermediate user, this guide will help you write better, faster, and more efficient R code.

What You’ll Learn

  1. Basic R: Fundamentals, shortcuts, and productivity tips
  2. Data Handling: Import, export, manipulation, and cleaning
  3. Big Data: Techniques for handling large datasets efficiently
  4. Data Visualization: Creating impactful graphics
  5. Time Series: Temporal data analysis and forecasting
  6. Geospatial Data: Mapping and spatial analysis
  7. Shiny Apps: Building interactive web applications

1. Basic R: Essential Tips and Tricks

1.1 Getting Started: Initial Setup

RStudio Keyboard Shortcuts (Must Know!)

# ESSENTIAL KEYBOARD SHORTCUTS (Works on Windows/Mac)
# 
# Code Execution:
# Ctrl/Cmd + Enter        - Run current line or selection
# Ctrl/Cmd + Shift + Enter - Run entire script
# Ctrl/Cmd + Shift + S    - Source entire script
# 
# Code Editing:
# Ctrl/Cmd + Shift + C    - Comment/uncomment lines
# Ctrl/Cmd + I            - Re-indent code
# Ctrl/Cmd + Shift + A    - Reformat code
# Alt + -                 - Insert assignment operator <-
# Ctrl/Cmd + Shift + M    - Insert pipe operator %>%
# 
# Navigation:
# Ctrl/Cmd + 1            - Move cursor to source editor
# Ctrl/Cmd + 2            - Move cursor to console
# Ctrl/Cmd + Shift + F    - Find in files
# Ctrl/Cmd + F            - Find/replace in current file
# 
# Code Completion:
# Tab                     - Auto-complete
# Ctrl/Cmd + Space        - Show function arguments
# F1                      - Open help for function under cursor
# 
# Session Management:
# Ctrl/Cmd + Shift + F10  - Restart R session
# Ctrl/Cmd + L            - Clear console

Setting Up Your R Environment

# 1. Set working directory (DO THIS FIRST!)
setwd("~/R_Projects/MyProject")  # Linux/Mac
setwd("C:/Users/YourName/R_Projects/MyProject")  # Windows

# Better: Use RStudio Projects (.Rproj files) - they auto-set working directory!

# 2. Check your current directory
getwd()

# 3. List files in directory
list.files()
dir()  # Same as list.files()

# 4. Create project structure
dir.create("data")
dir.create("scripts")
dir.create("output")
dir.create("figures")

# 5. Set global options
options(
  scipen = 999,              # Disable scientific notation
  digits = 3,                # Number of digits to display
  stringsAsFactors = FALSE,  # Don't auto-convert strings to factors
  repos = "https://cran.rstudio.com/"  # Default CRAN mirror
)

1.2 Basic R Dos and Don’ts

DO’s

#  DO: Use meaningful variable names
customer_age <- c(25, 30, 35, 40)  # GOOD
ca <- c(25, 30, 35, 40)            # BAD

#  DO: Use <- for assignment (not =)
x <- 5        # GOOD (R convention)
x = 5         # Works, but not preferred

#  DO: Add comments to explain your code
# Calculate average customer age
mean_age <- mean(customer_age)

#  DO: Use consistent naming convention
# Choose one and stick to it:
snake_case_variable <- "recommended"  # snake_case (recommended)
camelCaseVariable <- "also_good"      # camelCase
# PascalCaseVariable <- "for_functions"  # PascalCase

#  DO: Vectorize operations (avoid loops when possible)
# GOOD - Vectorized
numbers <- 1:1000
squares <- numbers^2

# BAD - Loop (slower)
squares <- numeric(1000)
for(i in 1:1000) {
  squares[i] <- i^2
}

#  DO: Use built-in functions
sum(1:100)              # GOOD
## [1] 5050
total <- 0; for(i in 1:100) total <- total + i  # BAD

#  DO: Check data structure regularly
str(mtcars)    # Structure
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
class(mtcars)  # Object class
## [1] "data.frame"
dim(mtcars)    # Dimensions
## [1] 32 11
head(mtcars)   # First few rows
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

DON’Ts

#  DON'T: Use attach() - it creates confusion
attach(mtcars)  # BAD - creates ambiguity
mpg             # Which mpg?
detach(mtcars)

# Instead, use:
mtcars$mpg      # GOOD - explicit
with(mtcars, mean(mpg))  # GOOD - clear scope

#  DON'T: Grow objects in loops
result <- c()
for(i in 1:1000) {
  result <- c(result, i^2)  # BAD - very slow!
}

# Instead, pre-allocate:
result <- numeric(1000)
for(i in 1:1000) {
  result[i] <- i^2  # GOOD - much faster
}

#  DON'T: Use T and F for TRUE and FALSE
x <- T   # BAD - T and F can be overwritten!
x <- F   # BAD

x <- TRUE   # GOOD
x <- FALSE  # GOOD

#  DON'T: Forget to set.seed() for reproducibility
sample(1:10, 5)  # BAD - different results each time

set.seed(123)
sample(1:10, 5)  # GOOD - reproducible

#  DON'T: Use == for comparing floating point numbers
0.1 + 0.2 == 0.3  # Returns FALSE! (floating point precision)

# Use all.equal() or near()
all.equal(0.1 + 0.2, 0.3)  # TRUE
dplyr::near(0.1 + 0.2, 0.3)  # TRUE

1.3 Package Management Best Practices

Installing and Loading Packages

#  GOOD: Check if package is installed before installing
if (!require("dplyr")) {
  install.packages("dplyr")
}

#  GOOD: Install multiple packages at once
packages <- c("dplyr", "ggplot2", "tidyr", "readr")
install.packages(packages)

#  GOOD: Use pacman for smart package loading
if (!require("pacman")) install.packages("pacman")
pacman::p_load(dplyr, ggplot2, tidyr, readr)  # Installs if needed, then loads

#  GOOD: Load packages at the start of your script
library(dplyr)
library(ggplot2)
library(tidyr)

#  BAD: Loading packages in the middle of your script
# ... makes it hard to track dependencies

#  GOOD: Use package::function() for rare function calls
# Avoids loading entire package
conflicted::conflict_prefer("filter", "dplyr")

# Check installed packages
installed.packages()[, c("Package", "Version")]

# Update all packages
update.packages(ask = FALSE)

# Remove package
remove.packages("package_name")

Managing Package Conflicts

library(dplyr)
library(MASS)  # MASS::select() conflicts with dplyr::select()

#  SOLUTION 1: Use package prefix
# MASS::select(iris, Species)
# dplyr::select(iris, Species)

#  SOLUTION 2: Use conflicted package
library(conflicted)
# conflict_prefer("select", "dplyr")
# conflict_prefer("filter", "dplyr")

# Now select() will always use dplyr version

1.4 Data Types and Structures

Understanding Basic Data Types

# Numeric
x <- 42
class(x)
## [1] "numeric"
# Integer (explicitly)
y <- 42L
class(y)
## [1] "integer"
# Character
name <- "John Doe"
class(name)
## [1] "character"
# Logical
is_active <- TRUE
class(is_active)
## [1] "logical"
# Factor (for categorical data)
gender <- factor(c("M", "F", "M", "F"))
class(gender)
## [1] "factor"
levels(gender)
## [1] "F" "M"
# Date
today <- Sys.Date()
class(today)
## [1] "Date"
# POSIXct (date-time)
now <- Sys.time()
class(now)
## [1] "POSIXct" "POSIXt"
# Check type
typeof(x)
## [1] "double"
mode(x)
## [1] "numeric"
class(x)
## [1] "numeric"
str(x)
##  num 42

Data Structures

# 1. VECTOR (1-dimensional, same type)
vec_numeric <- c(1, 2, 3, 4, 5)
vec_character <- c("a", "b", "c")
vec_logical <- c(TRUE, FALSE, TRUE)

# Named vectors
ages <- c(John = 25, Jane = 30, Bob = 35)
ages["John"]
## John 
##   25
# 2. MATRIX (2-dimensional, same type)
mat <- matrix(1:12, nrow = 3, ncol = 4)
mat
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# Access elements
mat[2, 3]     # Row 2, Column 3
## [1] 8
mat[2, ]      # All of row 2
## [1]  2  5  8 11
mat[, 3]      # All of column 3
## [1] 7 8 9
# 3. ARRAY (n-dimensional, same type)
arr <- array(1:24, dim = c(3, 4, 2))

# 4. LIST (can contain different types)
my_list <- list(
  numbers = 1:5,
  text = "hello",
  matrix = matrix(1:4, 2, 2),
  nested = list(a = 1, b = 2)
)

# Access list elements
my_list$numbers
## [1] 1 2 3 4 5
my_list[[1]]
## [1] 1 2 3 4 5
my_list[["numbers"]]
## [1] 1 2 3 4 5
# 5. DATA FRAME (2D, different types in columns)
df <- data.frame(
  id = 1:5,
  name = c("Alice", "Bob", "Charlie", "David", "Eve"),
  age = c(25, 30, 35, 40, 45),
  active = c(TRUE, TRUE, FALSE, TRUE, FALSE)
)

str(df)
## 'data.frame':    5 obs. of  4 variables:
##  $ id    : int  1 2 3 4 5
##  $ name  : chr  "Alice" "Bob" "Charlie" "David" ...
##  $ age   : num  25 30 35 40 45
##  $ active: logi  TRUE TRUE FALSE TRUE FALSE

Type Conversion Tricks

# Coercion hierarchy: logical < integer < numeric < character

# Convert between types
as.numeric("42")
## [1] 42
as.character(42)
## [1] "42"
as.logical(1)  # 0 = FALSE, non-zero = TRUE
## [1] TRUE
# Factor to numeric (TRICKY!)
f <- factor(c("10", "20", "30"))
as.numeric(f)  # WRONG! Returns 1, 2, 3
## [1] 1 2 3
as.numeric(as.character(f))  # CORRECT! Returns 10, 20, 30
## [1] 10 20 30
# Quick conversion table
conversion_examples <- data.frame(
  Operation = c("String to Number", "Number to String", "Factor to Numeric"),
  Code = c("as.numeric('42')", "as.character(42)", "as.numeric(as.character(f))"),
  stringsAsFactors = FALSE
)
print(conversion_examples)
##           Operation                        Code
## 1  String to Number            as.numeric('42')
## 2  Number to String            as.character(42)
## 3 Factor to Numeric as.numeric(as.character(f))

1.5 Control Structures and Functions

Conditional Statements

# IF-ELSE
x <- 10

if (x > 5) {
  print("x is greater than 5")
} else if (x == 5) {
  print("x equals 5")
} else {
  print("x is less than 5")
}
## [1] "x is greater than 5"
# Vectorized ifelse()
values <- c(1, 5, 10, 15, 20)
categories <- ifelse(values > 10, "High", "Low")
categories
## [1] "Low"  "Low"  "Low"  "High" "High"
# case_when() from dplyr (more readable for multiple conditions)
library(dplyr)
values_df <- data.frame(value = values)
values_df %>%
  mutate(category = case_when(
    value < 5 ~ "Very Low",
    value < 10 ~ "Low",
    value < 15 ~ "Medium",
    TRUE ~ "High"
  ))
##   value category
## 1     1 Very Low
## 2     5      Low
## 3    10   Medium
## 4    15     High
## 5    20     High

Loops (When You Need Them)

# FOR loop
for (i in 1:5) {
  print(paste("Iteration:", i))
}
## [1] "Iteration: 1"
## [1] "Iteration: 2"
## [1] "Iteration: 3"
## [1] "Iteration: 4"
## [1] "Iteration: 5"
# WHILE loop
count <- 1
while (count <= 5) {
  print(paste("Count:", count))
  count <- count + 1
}
## [1] "Count: 1"
## [1] "Count: 2"
## [1] "Count: 3"
## [1] "Count: 4"
## [1] "Count: 5"
# REPEAT loop (use with break)
count <- 1
repeat {
  print(paste("Count:", count))
  count <- count + 1
  if (count > 5) break
}
## [1] "Count: 1"
## [1] "Count: 2"
## [1] "Count: 3"
## [1] "Count: 4"
## [1] "Count: 5"
#  BETTER: Use apply family instead of loops
# apply(), lapply(), sapply(), mapply(), tapply()

# Example: Calculate mean of each column
df <- data.frame(
  a = 1:5,
  b = 6:10,
  c = 11:15
)

# Using loop (slower)
means <- numeric(ncol(df))
for (i in 1:ncol(df)) {
  means[i] <- mean(df[, i])
}

# Using apply (faster, cleaner)
means <- apply(df, 2, mean)  # 2 = columns
means
##  a  b  c 
##  3  8 13
# Using colMeans (even better!)
colMeans(df)
##  a  b  c 
##  3  8 13

Writing Functions

# Basic function
calculate_bmi <- function(weight_kg, height_m) {
  bmi <- weight_kg / (height_m^2)
  return(bmi)
}

calculate_bmi(70, 1.75)
## [1] 22.85714
# Function with default arguments
greet <- function(name, greeting = "Hello") {
  paste(greeting, name)
}

greet("Alice")
## [1] "Hello Alice"
greet("Bob", "Hi")
## [1] "Hi Bob"
# Function with multiple returns
statistics <- function(x) {
  result <- list(
    mean = mean(x),
    median = median(x),
    sd = sd(x),
    min = min(x),
    max = max(x)
  )
  return(result)
}

stats <- statistics(1:100)
stats$mean
## [1] 50.5
# Anonymous functions (lambda)
sapply(1:5, function(x) x^2)
## [1]  1  4  9 16 25
#  NEW: Pipe-friendly functions with {}
library(dplyr)
mtcars %>%
  {
    data.frame(
      mean_mpg = mean(.$mpg),
      mean_hp = mean(.$hp)
    )
  }
##   mean_mpg  mean_hp
## 1 20.09062 146.6875

Debugging Tips

# Print debugging
my_function <- function(x) {
  print(paste("Input:", x))  # Debug print
  result <- x * 2
  print(paste("Result:", result))  # Debug print
  return(result)
}

# Use browser() for interactive debugging
my_function <- function(x) {
  browser()  # Execution stops here
  result <- x * 2
  return(result)
}

# Use debug() to step through function
debug(my_function)
my_function(5)
undebug(my_function)

# Use traceback() after error
# ... error occurs ...
traceback()

# Use try() and tryCatch() for error handling
result <- try(log("not a number"), silent = TRUE)
if (inherits(result, "try-error")) {
  print("An error occurred!")
}

# Better error handling with tryCatch()
safe_log <- function(x) {
  tryCatch(
    {
      log(x)
    },
    error = function(e) {
      message("Error: ", e$message)
      return(NA)
    },
    warning = function(w) {
      message("Warning: ", w$message)
      return(log(x))
    }
  )
}

safe_log("abc")
safe_log(-5)

2. Data Handling: Import, Export, and Manipulation

2.1 Reading Data from Various Sources

CSV and Text Files

# Base R
df_base <- read.csv("data/file.csv")
df_base <- read.csv("data/file.csv", 
                    header = TRUE,
                    sep = ",",
                    stringsAsFactors = FALSE)

# readr (tidyverse - FASTER and better defaults)
library(readr)
df <- read_csv("data/file.csv")  # Better than read.csv()
df <- read_tsv("data/file.txt")  # Tab-separated
df <- read_delim("data/file.txt", delim = "|")  # Custom delimiter

# Read from URL
url <- "https://raw.githubusercontent.com/datasets/covid-19/master/data/countries-aggregated.csv"
df_url <- read_csv(url)

# Read with column specifications
df <- read_csv("data/file.csv",
               col_types = cols(
                 id = col_integer(),
                 name = col_character(),
                 date = col_date(format = "%Y-%m-%d"),
                 value = col_double()
               ))

# Skip rows
df <- read_csv("data/file.csv", skip = 2)

# Read only first n rows
df <- read_csv("data/file.csv", n_max = 1000)

Excel Files

# readxl package (part of tidyverse)
library(readxl)

# Read first sheet
df <- read_excel("data/file.xlsx")

# Read specific sheet
df <- read_excel("data/file.xlsx", sheet = "Sheet2")
df <- read_excel("data/file.xlsx", sheet = 2)

# List all sheets
excel_sheets("data/file.xlsx")

# Read all sheets at once
file_path <- "data/file.xlsx"
all_sheets <- excel_sheets(file_path)
data_list <- lapply(all_sheets, function(x) read_excel(file_path, sheet = x))
names(data_list) <- all_sheets

# Read specific range
df <- read_excel("data/file.xlsx", range = "A1:D10")

# Writing Excel files (openxlsx package)
library(openxlsx)
write.xlsx(df, "output/file.xlsx")

# Write multiple sheets
write.xlsx(list(Sheet1 = df1, Sheet2 = df2), "output/file.xlsx")

Database Connections

# SQLite
library(RSQLite)
con <- dbConnect(SQLite(), "data/database.sqlite")
df <- dbReadTable(con, "table_name")

# SQL query
df <- dbGetQuery(con, "SELECT * FROM table_name WHERE value > 100")

# Close connection
dbDisconnect(con)

# PostgreSQL
library(RPostgreSQL)
con <- dbConnect(PostgreSQL(),
                 dbname = "mydb",
                 host = "localhost",
                 port = 5432,
                 user = "username",
                 password = "password")

# MySQL
library(RMySQL)
con <- dbConnect(MySQL(),
                 dbname = "mydb",
                 host = "localhost",
                 user = "username",
                 password = "password")

# Generic DBI interface
library(DBI)
df <- dbReadTable(con, "table_name")
dbWriteTable(con, "new_table", df)

Other Formats

# JSON
library(jsonlite)
df <- fromJSON("data/file.json")
data_list <- fromJSON("data/file.json", simplifyDataFrame = FALSE)

# XML
library(XML)
doc <- xmlParse("data/file.xml")
df <- xmlToDataFrame(doc)

# SPSS, SAS, Stata (haven package)
library(haven)
df_spss <- read_sav("data/file.sav")    # SPSS
df_sas <- read_sas("data/file.sas7bdat")  # SAS
df_stata <- read_dta("data/file.dta")   # Stata

# RDS (R native format - FAST!)
saveRDS(df, "data/file.rds")
df <- readRDS("data/file.rds")

# RData (multiple objects)
save(df1, df2, df3, file = "data/workspace.RData")
load("data/workspace.RData")

# feather (fast format for Python/R)
library(feather)
write_feather(df, "data/file.feather")
df <- read_feather("data/file.feather")

# parquet (columnar format)
library(arrow)
write_parquet(df, "data/file.parquet")
df <- read_parquet("data/file.parquet")

2.2 Data Manipulation with dplyr

Essential dplyr Verbs

library(dplyr)

# Sample data
data("mtcars")
df <- mtcars

# 1. SELECT - Choose columns
df %>% select(mpg, cyl, hp)
##                      mpg cyl  hp
## Mazda RX4           21.0   6 110
## Mazda RX4 Wag       21.0   6 110
## Datsun 710          22.8   4  93
## Hornet 4 Drive      21.4   6 110
## Hornet Sportabout   18.7   8 175
## Valiant             18.1   6 105
## Duster 360          14.3   8 245
## Merc 240D           24.4   4  62
## Merc 230            22.8   4  95
## Merc 280            19.2   6 123
## Merc 280C           17.8   6 123
## Merc 450SE          16.4   8 180
## Merc 450SL          17.3   8 180
## Merc 450SLC         15.2   8 180
## Cadillac Fleetwood  10.4   8 205
## Lincoln Continental 10.4   8 215
## Chrysler Imperial   14.7   8 230
## Fiat 128            32.4   4  66
## Honda Civic         30.4   4  52
## Toyota Corolla      33.9   4  65
## Toyota Corona       21.5   4  97
## Dodge Challenger    15.5   8 150
## AMC Javelin         15.2   8 150
## Camaro Z28          13.3   8 245
## Pontiac Firebird    19.2   8 175
## Fiat X1-9           27.3   4  66
## Porsche 914-2       26.0   4  91
## Lotus Europa        30.4   4 113
## Ford Pantera L      15.8   8 264
## Ferrari Dino        19.7   6 175
## Maserati Bora       15.0   8 335
## Volvo 142E          21.4   4 109
df %>% select(starts_with("c"))
##                     cyl carb
## Mazda RX4             6    4
## Mazda RX4 Wag         6    4
## Datsun 710            4    1
## Hornet 4 Drive        6    1
## Hornet Sportabout     8    2
## Valiant               6    1
## Duster 360            8    4
## Merc 240D             4    2
## Merc 230              4    2
## Merc 280              6    4
## Merc 280C             6    4
## Merc 450SE            8    3
## Merc 450SL            8    3
## Merc 450SLC           8    3
## Cadillac Fleetwood    8    4
## Lincoln Continental   8    4
## Chrysler Imperial     8    4
## Fiat 128              4    1
## Honda Civic           4    2
## Toyota Corolla        4    1
## Toyota Corona         4    1
## Dodge Challenger      8    2
## AMC Javelin           8    2
## Camaro Z28            8    4
## Pontiac Firebird      8    2
## Fiat X1-9             4    1
## Porsche 914-2         4    2
## Lotus Europa          4    2
## Ford Pantera L        8    4
## Ferrari Dino          6    6
## Maserati Bora         8    8
## Volvo 142E            4    2
df %>% select(ends_with("p"))
##                      disp  hp
## Mazda RX4           160.0 110
## Mazda RX4 Wag       160.0 110
## Datsun 710          108.0  93
## Hornet 4 Drive      258.0 110
## Hornet Sportabout   360.0 175
## Valiant             225.0 105
## Duster 360          360.0 245
## Merc 240D           146.7  62
## Merc 230            140.8  95
## Merc 280            167.6 123
## Merc 280C           167.6 123
## Merc 450SE          275.8 180
## Merc 450SL          275.8 180
## Merc 450SLC         275.8 180
## Cadillac Fleetwood  472.0 205
## Lincoln Continental 460.0 215
## Chrysler Imperial   440.0 230
## Fiat 128             78.7  66
## Honda Civic          75.7  52
## Toyota Corolla       71.1  65
## Toyota Corona       120.1  97
## Dodge Challenger    318.0 150
## AMC Javelin         304.0 150
## Camaro Z28          350.0 245
## Pontiac Firebird    400.0 175
## Fiat X1-9            79.0  66
## Porsche 914-2       120.3  91
## Lotus Europa         95.1 113
## Ford Pantera L      351.0 264
## Ferrari Dino        145.0 175
## Maserati Bora       301.0 335
## Volvo 142E          121.0 109
df %>% select(contains("a"))
##                     drat am gear carb
## Mazda RX4           3.90  1    4    4
## Mazda RX4 Wag       3.90  1    4    4
## Datsun 710          3.85  1    4    1
## Hornet 4 Drive      3.08  0    3    1
## Hornet Sportabout   3.15  0    3    2
## Valiant             2.76  0    3    1
## Duster 360          3.21  0    3    4
## Merc 240D           3.69  0    4    2
## Merc 230            3.92  0    4    2
## Merc 280            3.92  0    4    4
## Merc 280C           3.92  0    4    4
## Merc 450SE          3.07  0    3    3
## Merc 450SL          3.07  0    3    3
## Merc 450SLC         3.07  0    3    3
## Cadillac Fleetwood  2.93  0    3    4
## Lincoln Continental 3.00  0    3    4
## Chrysler Imperial   3.23  0    3    4
## Fiat 128            4.08  1    4    1
## Honda Civic         4.93  1    4    2
## Toyota Corolla      4.22  1    4    1
## Toyota Corona       3.70  0    3    1
## Dodge Challenger    2.76  0    3    2
## AMC Javelin         3.15  0    3    2
## Camaro Z28          3.73  0    3    4
## Pontiac Firebird    3.08  0    3    2
## Fiat X1-9           4.08  1    4    1
## Porsche 914-2       4.43  1    5    2
## Lotus Europa        3.77  1    5    2
## Ford Pantera L      4.22  1    5    4
## Ferrari Dino        3.62  1    5    6
## Maserati Bora       3.54  1    5    8
## Volvo 142E          4.11  1    4    2
df %>% select(mpg:hp)  # Range
##                      mpg cyl  disp  hp
## Mazda RX4           21.0   6 160.0 110
## Mazda RX4 Wag       21.0   6 160.0 110
## Datsun 710          22.8   4 108.0  93
## Hornet 4 Drive      21.4   6 258.0 110
## Hornet Sportabout   18.7   8 360.0 175
## Valiant             18.1   6 225.0 105
## Duster 360          14.3   8 360.0 245
## Merc 240D           24.4   4 146.7  62
## Merc 230            22.8   4 140.8  95
## Merc 280            19.2   6 167.6 123
## Merc 280C           17.8   6 167.6 123
## Merc 450SE          16.4   8 275.8 180
## Merc 450SL          17.3   8 275.8 180
## Merc 450SLC         15.2   8 275.8 180
## Cadillac Fleetwood  10.4   8 472.0 205
## Lincoln Continental 10.4   8 460.0 215
## Chrysler Imperial   14.7   8 440.0 230
## Fiat 128            32.4   4  78.7  66
## Honda Civic         30.4   4  75.7  52
## Toyota Corolla      33.9   4  71.1  65
## Toyota Corona       21.5   4 120.1  97
## Dodge Challenger    15.5   8 318.0 150
## AMC Javelin         15.2   8 304.0 150
## Camaro Z28          13.3   8 350.0 245
## Pontiac Firebird    19.2   8 400.0 175
## Fiat X1-9           27.3   4  79.0  66
## Porsche 914-2       26.0   4 120.3  91
## Lotus Europa        30.4   4  95.1 113
## Ford Pantera L      15.8   8 351.0 264
## Ferrari Dino        19.7   6 145.0 175
## Maserati Bora       15.0   8 301.0 335
## Volvo 142E          21.4   4 121.0 109
df %>% select(-c(mpg, cyl))  # Exclude columns
##                      disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128             78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic          75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla       71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9            79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa         95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          121.0 109 4.11 2.780 18.60  1  1    4    2
# Helper functions
df %>% select(where(is.numeric))
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
df %>% select(everything())  # All columns
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
# 2. FILTER - Choose rows
df %>% filter(mpg > 20)
##                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Merc 240D      24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230       22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic    30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Fiat X1-9      27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
df %>% filter(mpg > 20 & cyl == 4)
##                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Merc 240D      24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230       22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic    30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Fiat X1-9      27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
df %>% filter(mpg > 20 | cyl == 4)
##                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Merc 240D      24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230       22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic    30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Fiat X1-9      27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
df %>% filter(cyl %in% c(4, 6))
##                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Merc 240D      24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230       22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280       19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C      17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic    30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona  21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Fiat X1-9      27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2  26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
df %>% filter(between(mpg, 15, 25))
##                    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Merc 240D         24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230          22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280          19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C         17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE        16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL        17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC       15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Toyota Corona     21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger  15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin       15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Pontiac Firebird  19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Ford Pantera L    15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino      19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora     15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E        21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
# 3. MUTATE - Create/modify columns
df %>%
  mutate(
    mpg_per_cyl = mpg / cyl,
    hp_category = ifelse(hp > 150, "High", "Low")
  )
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
##                     mpg_per_cyl hp_category
## Mazda RX4              3.500000         Low
## Mazda RX4 Wag          3.500000         Low
## Datsun 710             5.700000         Low
## Hornet 4 Drive         3.566667         Low
## Hornet Sportabout      2.337500        High
## Valiant                3.016667         Low
## Duster 360             1.787500        High
## Merc 240D              6.100000         Low
## Merc 230               5.700000         Low
## Merc 280               3.200000         Low
## Merc 280C              2.966667         Low
## Merc 450SE             2.050000        High
## Merc 450SL             2.162500        High
## Merc 450SLC            1.900000        High
## Cadillac Fleetwood     1.300000        High
## Lincoln Continental    1.300000        High
## Chrysler Imperial      1.837500        High
## Fiat 128               8.100000         Low
## Honda Civic            7.600000         Low
## Toyota Corolla         8.475000         Low
## Toyota Corona          5.375000         Low
## Dodge Challenger       1.937500         Low
## AMC Javelin            1.900000         Low
## Camaro Z28             1.662500        High
## Pontiac Firebird       2.400000        High
## Fiat X1-9              6.825000         Low
## Porsche 914-2          6.500000         Low
## Lotus Europa           7.600000         Low
## Ford Pantera L         1.975000        High
## Ferrari Dino           3.283333        High
## Maserati Bora          1.875000        High
## Volvo 142E             5.350000         Low
# 4. ARRANGE - Sort rows
df %>% arrange(mpg)  # Ascending
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
df %>% arrange(desc(mpg))  # Descending
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
df %>% arrange(cyl, desc(mpg))  # Multiple columns
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
# 5. SUMMARISE - Aggregate data
df %>%
  summarise(
    mean_mpg = mean(mpg),
    median_mpg = median(mpg),
    sd_mpg = sd(mpg),
    n = n()
  )
##   mean_mpg median_mpg   sd_mpg  n
## 1 20.09062       19.2 6.026948 32
# 6. GROUP_BY - Group operations
df %>%
  group_by(cyl) %>%
  summarise(
    mean_mpg = mean(mpg),
    mean_hp = mean(hp),
    count = n()
  )
## # A tibble: 3 × 4
##     cyl mean_mpg mean_hp count
##   <dbl>    <dbl>   <dbl> <int>
## 1     4     26.7    82.6    11
## 2     6     19.7   122.      7
## 3     8     15.1   209.     14
# 7. DISTINCT - Unique rows
df %>% distinct(cyl)
##                   cyl
## Mazda RX4           6
## Datsun 710          4
## Hornet Sportabout   8
df %>% distinct(cyl, gear)
##                   cyl gear
## Mazda RX4           6    4
## Datsun 710          4    4
## Hornet 4 Drive      6    3
## Hornet Sportabout   8    3
## Toyota Corona       4    3
## Porsche 914-2       4    5
## Ford Pantera L      8    5
## Ferrari Dino        6    5
# 8. SLICE - Select rows by position
df %>% slice(1:5)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
df %>% slice_head(n = 5)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
df %>% slice_tail(n = 5)
##                 mpg cyl  disp  hp drat    wt qsec vs am gear carb
## Lotus Europa   30.4   4  95.1 113 3.77 1.513 16.9  1  1    5    2
## Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.5  0  1    5    4
## Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.5  0  1    5    6
## Maserati Bora  15.0   8 301.0 335 3.54 3.570 14.6  0  1    5    8
## Volvo 142E     21.4   4 121.0 109 4.11 2.780 18.6  1  1    4    2
df %>% slice_max(mpg, n = 5)
##                 mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Toyota Corolla 33.9   4 71.1  65 4.22 1.835 19.90  1  1    4    1
## Fiat 128       32.4   4 78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic    30.4   4 75.7  52 4.93 1.615 18.52  1  1    4    2
## Lotus Europa   30.4   4 95.1 113 3.77 1.513 16.90  1  1    5    2
## Fiat X1-9      27.3   4 79.0  66 4.08 1.935 18.90  1  1    4    1
df %>% slice_sample(n = 5)
##                   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Lotus Europa     30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Pontiac Firebird 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat 128         32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Mazda RX4 Wag    21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Merc 450SLC      15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3

Advanced dplyr Techniques

# Rename columns
df %>% rename(miles_per_gallon = mpg)
##                     miles_per_gallon cyl  disp  hp drat    wt  qsec vs am gear
## Mazda RX4                       21.0   6 160.0 110 3.90 2.620 16.46  0  1    4
## Mazda RX4 Wag                   21.0   6 160.0 110 3.90 2.875 17.02  0  1    4
## Datsun 710                      22.8   4 108.0  93 3.85 2.320 18.61  1  1    4
## Hornet 4 Drive                  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3
## Hornet Sportabout               18.7   8 360.0 175 3.15 3.440 17.02  0  0    3
## Valiant                         18.1   6 225.0 105 2.76 3.460 20.22  1  0    3
## Duster 360                      14.3   8 360.0 245 3.21 3.570 15.84  0  0    3
## Merc 240D                       24.4   4 146.7  62 3.69 3.190 20.00  1  0    4
## Merc 230                        22.8   4 140.8  95 3.92 3.150 22.90  1  0    4
## Merc 280                        19.2   6 167.6 123 3.92 3.440 18.30  1  0    4
## Merc 280C                       17.8   6 167.6 123 3.92 3.440 18.90  1  0    4
## Merc 450SE                      16.4   8 275.8 180 3.07 4.070 17.40  0  0    3
## Merc 450SL                      17.3   8 275.8 180 3.07 3.730 17.60  0  0    3
## Merc 450SLC                     15.2   8 275.8 180 3.07 3.780 18.00  0  0    3
## Cadillac Fleetwood              10.4   8 472.0 205 2.93 5.250 17.98  0  0    3
## Lincoln Continental             10.4   8 460.0 215 3.00 5.424 17.82  0  0    3
## Chrysler Imperial               14.7   8 440.0 230 3.23 5.345 17.42  0  0    3
## Fiat 128                        32.4   4  78.7  66 4.08 2.200 19.47  1  1    4
## Honda Civic                     30.4   4  75.7  52 4.93 1.615 18.52  1  1    4
## Toyota Corolla                  33.9   4  71.1  65 4.22 1.835 19.90  1  1    4
## Toyota Corona                   21.5   4 120.1  97 3.70 2.465 20.01  1  0    3
## Dodge Challenger                15.5   8 318.0 150 2.76 3.520 16.87  0  0    3
## AMC Javelin                     15.2   8 304.0 150 3.15 3.435 17.30  0  0    3
## Camaro Z28                      13.3   8 350.0 245 3.73 3.840 15.41  0  0    3
## Pontiac Firebird                19.2   8 400.0 175 3.08 3.845 17.05  0  0    3
## Fiat X1-9                       27.3   4  79.0  66 4.08 1.935 18.90  1  1    4
## Porsche 914-2                   26.0   4 120.3  91 4.43 2.140 16.70  0  1    5
## Lotus Europa                    30.4   4  95.1 113 3.77 1.513 16.90  1  1    5
## Ford Pantera L                  15.8   8 351.0 264 4.22 3.170 14.50  0  1    5
## Ferrari Dino                    19.7   6 145.0 175 3.62 2.770 15.50  0  1    5
## Maserati Bora                   15.0   8 301.0 335 3.54 3.570 14.60  0  1    5
## Volvo 142E                      21.4   4 121.0 109 4.11 2.780 18.60  1  1    4
##                     carb
## Mazda RX4              4
## Mazda RX4 Wag          4
## Datsun 710             1
## Hornet 4 Drive         1
## Hornet Sportabout      2
## Valiant                1
## Duster 360             4
## Merc 240D              2
## Merc 230               2
## Merc 280               4
## Merc 280C              4
## Merc 450SE             3
## Merc 450SL             3
## Merc 450SLC            3
## Cadillac Fleetwood     4
## Lincoln Continental    4
## Chrysler Imperial      4
## Fiat 128               1
## Honda Civic            2
## Toyota Corolla         1
## Toyota Corona          1
## Dodge Challenger       2
## AMC Javelin            2
## Camaro Z28             4
## Pontiac Firebird       2
## Fiat X1-9              1
## Porsche 914-2          2
## Lotus Europa           2
## Ford Pantera L         4
## Ferrari Dino           6
## Maserati Bora          8
## Volvo 142E             2
# Relocate columns
df %>% relocate(hp, .before = mpg)
##                      hp  mpg cyl  disp drat    wt  qsec vs am gear carb
## Mazda RX4           110 21.0   6 160.0 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       110 21.0   6 160.0 3.90 2.875 17.02  0  1    4    4
## Datsun 710           93 22.8   4 108.0 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      110 21.4   6 258.0 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   175 18.7   8 360.0 3.15 3.440 17.02  0  0    3    2
## Valiant             105 18.1   6 225.0 2.76 3.460 20.22  1  0    3    1
## Duster 360          245 14.3   8 360.0 3.21 3.570 15.84  0  0    3    4
## Merc 240D            62 24.4   4 146.7 3.69 3.190 20.00  1  0    4    2
## Merc 230             95 22.8   4 140.8 3.92 3.150 22.90  1  0    4    2
## Merc 280            123 19.2   6 167.6 3.92 3.440 18.30  1  0    4    4
## Merc 280C           123 17.8   6 167.6 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          180 16.4   8 275.8 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          180 17.3   8 275.8 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         180 15.2   8 275.8 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  205 10.4   8 472.0 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 215 10.4   8 460.0 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   230 14.7   8 440.0 3.23 5.345 17.42  0  0    3    4
## Fiat 128             66 32.4   4  78.7 4.08 2.200 19.47  1  1    4    1
## Honda Civic          52 30.4   4  75.7 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla       65 33.9   4  71.1 4.22 1.835 19.90  1  1    4    1
## Toyota Corona        97 21.5   4 120.1 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    150 15.5   8 318.0 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         150 15.2   8 304.0 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          245 13.3   8 350.0 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    175 19.2   8 400.0 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9            66 27.3   4  79.0 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2        91 26.0   4 120.3 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        113 30.4   4  95.1 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      264 15.8   8 351.0 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        175 19.7   6 145.0 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       335 15.0   8 301.0 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          109 21.4   4 121.0 4.11 2.780 18.60  1  1    4    2
df %>% relocate(cyl, .after = last_col())
##                      mpg  disp  hp drat    wt  qsec vs am gear carb cyl
## Mazda RX4           21.0 160.0 110 3.90 2.620 16.46  0  1    4    4   6
## Mazda RX4 Wag       21.0 160.0 110 3.90 2.875 17.02  0  1    4    4   6
## Datsun 710          22.8 108.0  93 3.85 2.320 18.61  1  1    4    1   4
## Hornet 4 Drive      21.4 258.0 110 3.08 3.215 19.44  1  0    3    1   6
## Hornet Sportabout   18.7 360.0 175 3.15 3.440 17.02  0  0    3    2   8
## Valiant             18.1 225.0 105 2.76 3.460 20.22  1  0    3    1   6
## Duster 360          14.3 360.0 245 3.21 3.570 15.84  0  0    3    4   8
## Merc 240D           24.4 146.7  62 3.69 3.190 20.00  1  0    4    2   4
## Merc 230            22.8 140.8  95 3.92 3.150 22.90  1  0    4    2   4
## Merc 280            19.2 167.6 123 3.92 3.440 18.30  1  0    4    4   6
## Merc 280C           17.8 167.6 123 3.92 3.440 18.90  1  0    4    4   6
## Merc 450SE          16.4 275.8 180 3.07 4.070 17.40  0  0    3    3   8
## Merc 450SL          17.3 275.8 180 3.07 3.730 17.60  0  0    3    3   8
## Merc 450SLC         15.2 275.8 180 3.07 3.780 18.00  0  0    3    3   8
## Cadillac Fleetwood  10.4 472.0 205 2.93 5.250 17.98  0  0    3    4   8
## Lincoln Continental 10.4 460.0 215 3.00 5.424 17.82  0  0    3    4   8
## Chrysler Imperial   14.7 440.0 230 3.23 5.345 17.42  0  0    3    4   8
## Fiat 128            32.4  78.7  66 4.08 2.200 19.47  1  1    4    1   4
## Honda Civic         30.4  75.7  52 4.93 1.615 18.52  1  1    4    2   4
## Toyota Corolla      33.9  71.1  65 4.22 1.835 19.90  1  1    4    1   4
## Toyota Corona       21.5 120.1  97 3.70 2.465 20.01  1  0    3    1   4
## Dodge Challenger    15.5 318.0 150 2.76 3.520 16.87  0  0    3    2   8
## AMC Javelin         15.2 304.0 150 3.15 3.435 17.30  0  0    3    2   8
## Camaro Z28          13.3 350.0 245 3.73 3.840 15.41  0  0    3    4   8
## Pontiac Firebird    19.2 400.0 175 3.08 3.845 17.05  0  0    3    2   8
## Fiat X1-9           27.3  79.0  66 4.08 1.935 18.90  1  1    4    1   4
## Porsche 914-2       26.0 120.3  91 4.43 2.140 16.70  0  1    5    2   4
## Lotus Europa        30.4  95.1 113 3.77 1.513 16.90  1  1    5    2   4
## Ford Pantera L      15.8 351.0 264 4.22 3.170 14.50  0  1    5    4   8
## Ferrari Dino        19.7 145.0 175 3.62 2.770 15.50  0  1    5    6   6
## Maserati Bora       15.0 301.0 335 3.54 3.570 14.60  0  1    5    8   8
## Volvo 142E          21.4 121.0 109 4.11 2.780 18.60  1  1    4    2   4
# Count occurrences
df %>% count(cyl)
##   cyl  n
## 1   4 11
## 2   6  7
## 3   8 14
df %>% count(cyl, gear)
##   cyl gear  n
## 1   4    3  1
## 2   4    4  8
## 3   4    5  2
## 4   6    3  2
## 5   6    4  4
## 6   6    5  1
## 7   8    3 12
## 8   8    5  2
# Add row numbers
df %>% mutate(row_id = row_number())
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb row_id
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4      1
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4      2
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1      3
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1      4
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2      5
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1      6
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4      7
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2      8
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2      9
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4     10
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4     11
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3     12
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3     13
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3     14
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4     15
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4     16
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4     17
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1     18
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2     19
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1     20
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1     21
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2     22
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2     23
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4     24
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2     25
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1     26
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2     27
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2     28
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4     29
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6     30
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8     31
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2     32
# Cumulative operations
df %>%
  arrange(mpg) %>%
  mutate(
    cumsum_mpg = cumsum(mpg),
    rank_mpg = min_rank(mpg),
    percent_rank_mpg = percent_rank(mpg)
  )
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
##                     cumsum_mpg rank_mpg percent_rank_mpg
## Cadillac Fleetwood        10.4        1       0.00000000
## Lincoln Continental       20.8        1       0.00000000
## Camaro Z28                34.1        3       0.06451613
## Duster 360                48.4        4       0.09677419
## Chrysler Imperial         63.1        5       0.12903226
## Maserati Bora             78.1        6       0.16129032
## Merc 450SLC               93.3        7       0.19354839
## AMC Javelin              108.5        7       0.19354839
## Dodge Challenger         124.0        9       0.25806452
## Ford Pantera L           139.8       10       0.29032258
## Merc 450SE               156.2       11       0.32258065
## Merc 450SL               173.5       12       0.35483871
## Merc 280C                191.3       13       0.38709677
## Valiant                  209.4       14       0.41935484
## Hornet Sportabout        228.1       15       0.45161290
## Merc 280                 247.3       16       0.48387097
## Pontiac Firebird         266.5       16       0.48387097
## Ferrari Dino             286.2       18       0.54838710
## Mazda RX4                307.2       19       0.58064516
## Mazda RX4 Wag            328.2       19       0.58064516
## Hornet 4 Drive           349.6       21       0.64516129
## Volvo 142E               371.0       21       0.64516129
## Toyota Corona            392.5       23       0.70967742
## Datsun 710               415.3       24       0.74193548
## Merc 230                 438.1       24       0.74193548
## Merc 240D                462.5       26       0.80645161
## Porsche 914-2            488.5       27       0.83870968
## Fiat X1-9                515.8       28       0.87096774
## Honda Civic              546.2       29       0.90322581
## Lotus Europa             576.6       29       0.90322581
## Fiat 128                 609.0       31       0.96774194
## Toyota Corolla           642.9       32       1.00000000
# Window functions
df %>%
  group_by(cyl) %>%
  mutate(
    mpg_rank_in_group = rank(mpg),
    mpg_vs_group_mean = mpg - mean(mpg)
  )
## # A tibble: 32 × 13
## # Groups:   cyl [3]
##      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
##  2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
##  3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
##  4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
##  5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
##  6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
##  7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
##  8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
##  9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
## 10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
## # ℹ 22 more rows
## # ℹ 2 more variables: mpg_rank_in_group <dbl>, mpg_vs_group_mean <dbl>
# Multiple summaries
df %>%
  group_by(cyl) %>%
  summarise(
    across(c(mpg, hp), list(mean = mean, sd = sd))
  )
## # A tibble: 3 × 5
##     cyl mpg_mean mpg_sd hp_mean hp_sd
##   <dbl>    <dbl>  <dbl>   <dbl> <dbl>
## 1     4     26.7   4.51    82.6  20.9
## 2     6     19.7   1.45   122.   24.3
## 3     8     15.1   2.56   209.   51.0
# Conditional mutations
df %>%
  mutate(
    efficiency = case_when(
      mpg > 25 ~ "High",
      mpg > 20 ~ "Medium",
      mpg > 15 ~ "Low",
      TRUE ~ "Very Low"
    )
  )
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
##                     efficiency
## Mazda RX4               Medium
## Mazda RX4 Wag           Medium
## Datsun 710              Medium
## Hornet 4 Drive          Medium
## Hornet Sportabout          Low
## Valiant                    Low
## Duster 360            Very Low
## Merc 240D               Medium
## Merc 230                Medium
## Merc 280                   Low
## Merc 280C                  Low
## Merc 450SE                 Low
## Merc 450SL                 Low
## Merc 450SLC                Low
## Cadillac Fleetwood    Very Low
## Lincoln Continental   Very Low
## Chrysler Imperial     Very Low
## Fiat 128                  High
## Honda Civic               High
## Toyota Corolla            High
## Toyota Corona           Medium
## Dodge Challenger           Low
## AMC Javelin                Low
## Camaro Z28            Very Low
## Pontiac Firebird           Low
## Fiat X1-9                 High
## Porsche 914-2             High
## Lotus Europa              High
## Ford Pantera L             Low
## Ferrari Dino               Low
## Maserati Bora         Very Low
## Volvo 142E              Medium

Joining Data

# Sample data
customers <- data.frame(
  id = 1:5,
  name = c("Alice", "Bob", "Charlie", "David", "Eve")
)

orders <- data.frame(
  order_id = 1:6,
  customer_id = c(1, 1, 2, 3, 3, 6),
  amount = c(100, 150, 200, 50, 75, 300)
)

# INNER JOIN - Only matching rows
inner_join(customers, orders, by = c("id" = "customer_id"))
##   id    name order_id amount
## 1  1   Alice        1    100
## 2  1   Alice        2    150
## 3  2     Bob        3    200
## 4  3 Charlie        4     50
## 5  3 Charlie        5     75
# LEFT JOIN - All from left, matching from right
left_join(customers, orders, by = c("id" = "customer_id"))
##   id    name order_id amount
## 1  1   Alice        1    100
## 2  1   Alice        2    150
## 3  2     Bob        3    200
## 4  3 Charlie        4     50
## 5  3 Charlie        5     75
## 6  4   David       NA     NA
## 7  5     Eve       NA     NA
# RIGHT JOIN - All from right, matching from left
right_join(customers, orders, by = c("id" = "customer_id"))
##   id    name order_id amount
## 1  1   Alice        1    100
## 2  1   Alice        2    150
## 3  2     Bob        3    200
## 4  3 Charlie        4     50
## 5  3 Charlie        5     75
## 6  6    <NA>        6    300
# FULL JOIN - All rows from both
full_join(customers, orders, by = c("id" = "customer_id"))
##   id    name order_id amount
## 1  1   Alice        1    100
## 2  1   Alice        2    150
## 3  2     Bob        3    200
## 4  3 Charlie        4     50
## 5  3 Charlie        5     75
## 6  4   David       NA     NA
## 7  5     Eve       NA     NA
## 8  6    <NA>        6    300
# ANTI JOIN - Rows in left NOT in right
anti_join(customers, orders, by = c("id" = "customer_id"))
##   id  name
## 1  4 David
## 2  5   Eve
# SEMI JOIN - Rows in left that have match in right
semi_join(customers, orders, by = c("id" = "customer_id"))
##   id    name
## 1  1   Alice
## 2  2     Bob
## 3  3 Charlie

2.3 Data Cleaning Tricks

Handling Missing Values

# Create sample data with missing values
library(tidyr)
df <- data.frame(
  id = 1:10,
  value1 = c(1, 2, NA, 4, 5, NA, 7, 8, 9, 10),
  value2 = c(NA, 2, 3, NA, 5, 6, 7, NA, 9, 10)
)

# Check for missing values
sum(is.na(df))
## [1] 5
colSums(is.na(df))
##     id value1 value2 
##      0      2      3
complete.cases(df)
##  [1] FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE  TRUE
# Remove rows with ANY missing values
df %>% na.omit()
##    id value1 value2
## 2   2      2      2
## 5   5      5      5
## 7   7      7      7
## 9   9      9      9
## 10 10     10     10
df %>% filter(complete.cases(.))
##   id value1 value2
## 1  2      2      2
## 2  5      5      5
## 3  7      7      7
## 4  9      9      9
## 5 10     10     10
# Remove rows with missing in specific column
df %>% filter(!is.na(value1))
##   id value1 value2
## 1  1      1     NA
## 2  2      2      2
## 3  4      4     NA
## 4  5      5      5
## 5  7      7      7
## 6  8      8     NA
## 7  9      9      9
## 8 10     10     10
# Replace NA with value
df %>% 
  mutate(value1 = replace_na(value1, 0))
##    id value1 value2
## 1   1      1     NA
## 2   2      2      2
## 3   3      0      3
## 4   4      4     NA
## 5   5      5      5
## 6   6      0      6
## 7   7      7      7
## 8   8      8     NA
## 9   9      9      9
## 10 10     10     10
# Replace NA with mean
df %>%
  mutate(value1 = ifelse(is.na(value1), mean(value1, na.rm = TRUE), value1))
##    id value1 value2
## 1   1   1.00     NA
## 2   2   2.00      2
## 3   3   5.75      3
## 4   4   4.00     NA
## 5   5   5.00      5
## 6   6   5.75      6
## 7   7   7.00      7
## 8   8   8.00     NA
## 9   9   9.00      9
## 10 10  10.00     10
# Fill NA with previous/next value
df %>%
  tidyr::fill(value1, .direction = "down")
##    id value1 value2
## 1   1      1     NA
## 2   2      2      2
## 3   3      2      3
## 4   4      4     NA
## 5   5      5      5
## 6   6      5      6
## 7   7      7      7
## 8   8      8     NA
## 9   9      9      9
## 10 10     10     10
# Count missing by group
df %>%
  group_by(id %% 2) %>%
  summarise(
    missing_value1 = sum(is.na(value1)),
    missing_value2 = sum(is.na(value2))
  )
## # A tibble: 2 × 3
##   `id%%2` missing_value1 missing_value2
##     <dbl>          <int>          <int>
## 1       0              1              2
## 2       1              1              1

Handling Duplicates

# Create data with duplicates
df <- data.frame(
  id = c(1, 2, 2, 3, 4, 4, 4),
  name = c("A", "B", "B", "C", "D", "D", "D"),
  value = c(10, 20, 20, 30, 40, 40, 45)
)

# Find duplicates
df %>% filter(duplicated(.) | duplicated(., fromLast = TRUE))
##   id name value
## 1  2    B    20
## 2  2    B    20
## 3  4    D    40
## 4  4    D    40
# Remove duplicates (keep first)
df %>% distinct()
##   id name value
## 1  1    A    10
## 2  2    B    20
## 3  3    C    30
## 4  4    D    40
## 5  4    D    45
# Remove based on specific columns
df %>% distinct(id, name, .keep_all = TRUE)
##   id name value
## 1  1    A    10
## 2  2    B    20
## 3  3    C    30
## 4  4    D    40
# Keep row with max value per group
df %>%
  group_by(id, name) %>%
  slice_max(value, n = 1) %>%
  ungroup()
## # A tibble: 5 × 3
##      id name  value
##   <dbl> <chr> <dbl>
## 1     1 A        10
## 2     2 B        20
## 3     2 B        20
## 4     3 C        30
## 5     4 D        45

String Cleaning

library(stringr)

# Sample messy data
text <- c("  Hello World  ", "UPPER case", "under_score", "123-456")

# Trim whitespace
str_trim(text)
## [1] "Hello World" "UPPER case"  "under_score" "123-456"
# Change case
str_to_lower(text)
## [1] "  hello world  " "upper case"      "under_score"     "123-456"
str_to_upper(text)
## [1] "  HELLO WORLD  " "UPPER CASE"      "UNDER_SCORE"     "123-456"
str_to_title(text)
## [1] "  Hello World  " "Upper Case"      "Under_score"     "123-456"
# Replace patterns
str_replace(text, " ", "_")
## [1] "_ Hello World  " "UPPER_case"      "under_score"     "123-456"
str_replace_all(text, "[0-9]", "X")
## [1] "  Hello World  " "UPPER case"      "under_score"     "XXX-XXX"
# Extract patterns
str_extract(text, "[0-9]+")
## [1] NA    NA    NA    "123"
str_extract_all(text, "[0-9]")
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## character(0)
## 
## [[4]]
## [1] "1" "2" "3" "4" "5" "6"
# Detect patterns
str_detect(text, "[0-9]")
## [1] FALSE FALSE FALSE  TRUE
# Split strings
str_split(text, " ")
## [[1]]
## [1] ""      ""      "Hello" "World" ""      ""     
## 
## [[2]]
## [1] "UPPER" "case" 
## 
## [[3]]
## [1] "under_score"
## 
## [[4]]
## [1] "123-456"
# Concatenate
str_c(text, collapse = " | ")
## [1] "  Hello World   | UPPER case | under_score | 123-456"
paste(text, collapse = " | ")
## [1] "  Hello World   | UPPER case | under_score | 123-456"
paste0("ID_", 1:4)  # No separator
## [1] "ID_1" "ID_2" "ID_3" "ID_4"

2.4 Exporting Data

Writing Files

# CSV
write.csv(df, "output/file.csv", row.names = FALSE)
write_csv(df, "output/file.csv")  # readr version (faster)

# Excel
library(openxlsx)
write.xlsx(df, "output/file.xlsx")

# Multiple sheets
write.xlsx(list(Sheet1 = df1, Sheet2 = df2), "output/file.xlsx")

# RDS (recommended for R-to-R)
saveRDS(df, "output/file.rds")

# RData (multiple objects)
save(df1, df2, df3, file = "output/workspace.RData")

# Tab-separated
write.table(df, "output/file.txt", sep = "\t", row.names = FALSE)

# JSON
library(jsonlite)
write_json(df, "output/file.json")

# Parquet (efficient for large data)
library(arrow)
write_parquet(df, "output/file.parquet")

3. Big Data Handling Techniques

3.1 Memory Management

Understanding Memory Usage

# Check object size
object.size(mtcars)
## 7208 bytes
print(object.size(mtcars), units = "Kb")
## 7 Kb
# List all objects and their sizes
sort(sapply(ls(), function(x) object.size(get(x))), decreasing = TRUE)
##             squares              mtcars             numbers               greet 
##                8048                7208                4048                4024 
##          statistics       calculate_bmi conversion_examples                  df 
##                2744                1904                1400                1400 
##             my_list           customers              orders               stats 
##                1384                1208                1128                 864 
##           values_df                   f              gender                ages 
##                 776                 648                 576                 440 
##               means                 arr                 now                text 
##                 440                 352                 344                 328 
##               today                 mat       vec_character          categories 
##                 280                 264                 248                 208 
##   camelCaseVariable                name snake_case_variable                   x 
##                 120                 120                 120                 112 
##              values         vec_numeric                  ca        customer_age 
##                  96                  96                  80                  80 
##         vec_logical               count                   i           is_active 
##                  64                  56                  56                  56 
##            mean_age               total                   y 
##                  56                  56                  56
# Remove objects
rm(large_object)

# Clear workspace
# rm(list = ls())  # Use with caution!

# Garbage collection (free up memory)
gc()
##           used (Mb) gc trigger (Mb) max used (Mb)
## Ncells  925470 49.5    1801071 96.2  1335235 71.4
## Vcells 1728715 13.2    8388608 64.0  2728732 20.9
# Check memory limit
memory.limit()  # Windows only
## [1] Inf

Memory-Efficient Data Types

# Use appropriate data types
# Character uses more memory than factor (for categorical data)

# Bad: Character
vec_char <- rep(c("A", "B", "C"), 1000)
object.size(vec_char)
## 24216 bytes
# Good: Factor
vec_factor <- factor(rep(c("A", "B", "C"), 1000))
object.size(vec_factor)
## 12632 bytes
# Integer vs Numeric
vec_numeric <- 1:10000  # Actually integer
object.size(vec_numeric)
## 40048 bytes
vec_numeric2 <- as.numeric(1:10000)  # Actual numeric
object.size(vec_numeric2)
## 80048 bytes
# Use bit64 for large integers
library(bit64)
large_integers <- as.integer64(1:1000)

3.2 Working with Large Files

Chunked Reading

# Read in chunks using readr
library(readr)

# Define chunk size
chunk_size <- 10000

# Read and process in chunks
process_chunk <- function(chunk, pos) {
  # Your processing here
  summarised <- chunk %>%
    group_by(category) %>%
    summarise(mean_value = mean(value))
  return(summarised)
}

# Read file in chunks
results <- read_csv_chunked(
  "data/large_file.csv",
  callback = DataFrameCallback$new(process_chunk),
  chunk_size = chunk_size
)

# Alternative: readr with callback
f <- function(x, pos) {
  subset(x, value > 100)
}
large_subset <- read_csv_chunked("data/large_file.csv", 
                                  DataFrameCallback$new(f),
                                  chunk_size = 10000)

Using data.table for Speed

library(data.table)

# Create sample data
set.seed(123)
dt <- data.table(
  id = 1:1000000,
  group = sample(LETTERS[1:5], 1000000, replace = TRUE),
  value = rnorm(1000000)
)

# Fast subsetting (by reference)
dt[value > 0]
##              id  group     value
##           <int> <char>     <num>
##      1:       1      C 0.6795146
##      2:       3      B 0.5764687
##      3:       4      B 1.4719505
##      4:      11      E 1.6074790
##      5:      12      C 1.4891379
##     ---                         
## 501065:  999981      B 1.3670128
## 501066:  999986      D 2.8043210
## 501067:  999989      E 1.4282585
## 501068:  999999      E 1.6899913
## 501069: 1000000      D 2.8570567
# Fast aggregation
dt[, .(mean_value = mean(value)), by = group]
##     group  mean_value
##    <char>       <num>
## 1:      C 0.002219641
## 2:      B 0.004007285
## 3:      E 0.001370850
## 4:      D 0.003229437
## 5:      A 0.001607565
# Multiple aggregations
dt[, .(mean_val = mean(value),
       sd_val = sd(value),
       count = .N), 
   by = group]
##     group    mean_val    sd_val  count
##    <char>       <num>     <num>  <int>
## 1:      C 0.002219641 0.9997533 199757
## 2:      B 0.004007285 1.0027697 199665
## 3:      E 0.001370850 1.0002375 200292
## 4:      D 0.003229437 0.9999474 200212
## 5:      A 0.001607565 0.9975856 200074
# Update by reference (no copy!)
dt[, new_column := value * 2]

# Conditional update
dt[value > 0, category := "positive"]
dt[value <= 0, category := "non-positive"]

# Remove column
dt[, category := NULL]

# Chaining operations
dt[value > 0][order(-value)][, .(id, value)]
##             id        value
##          <int>        <num>
##      1: 193504 4.988298e+00
##      2: 444817 4.729713e+00
##      3:  99193 4.568838e+00
##      4: 462545 4.498943e+00
##      5:  20296 4.477925e+00
##     ---                    
## 501065:  81872 1.212652e-05
## 501066: 757893 1.163082e-05
## 501067: 353926 1.101934e-05
## 501068: 913215 7.906741e-06
## 501069: 392918 1.790613e-06
# Set key for fast joins
setkey(dt, group)

# Fast merge
dt2 <- data.table(
  group = LETTERS[1:5],
  group_name = paste("Group", LETTERS[1:5])
)
setkey(dt2, group)
merged <- dt[dt2]

Using Arrow for Large Files

library(arrow)
library(dplyr)

# Read parquet file (doesn't load into memory)
dataset <- open_dataset("data/large_file.parquet")

# Query without loading full data
result <- dataset %>%
  filter(value > 100) %>%
  group_by(category) %>%
  summarise(mean_value = mean(value)) %>%
  collect()  # Only now is data loaded

# Read multiple parquet files as one dataset
dataset <- open_dataset("data/partitioned_data/")

# Write partitioned parquet
df %>%
  group_by(year, month) %>%
  write_dataset("data/partitioned_data/", format = "parquet")

3.3 Parallel Processing

Using parallel Package

library(parallel)

# Detect number of cores
num_cores <- detectCores()
print(paste("Available cores:", num_cores))

# Create cluster
cl <- makeCluster(num_cores - 1)  # Leave one core free

# Parallel lapply
results <- parLapply(cl, 1:1000, function(x) {
  # Your computation here
  x^2
})

# Stop cluster when done
stopCluster(cl)

# Using mclapply (Unix/Mac only)
results <- mclapply(1:1000, function(x) x^2, mc.cores = num_cores - 1)

# Example: Parallel data processing
library(doParallel)
registerDoParallel(cores = num_cores - 1)

library(foreach)
results <- foreach(i = 1:1000, .combine = rbind) %dopar% {
  # Your processing
  data.frame(id = i, result = i^2)
}

stopImplicitCluster()

Using furrr for Parallel purrr

library(furrr)
library(purrr)

# Setup parallel processing
plan(multisession, workers = 4)

# Regular purrr
result_sequential <- map(1:100, ~ slow_function(.x))

# Parallel purrr
result_parallel <- future_map(1:100, ~ slow_function(.x))

# With progress bar
result_parallel <- future_map(1:100, ~ slow_function(.x), .progress = TRUE)

3.4 Database-like Operations

Using dbplyr

library(dbplyr)
library(RSQLite)

# Connect to database
con <- dbConnect(SQLite(), "data/large_database.sqlite")

# Create lazy table reference
db_table <- tbl(con, "large_table")

# All operations are lazy (not executed until needed)
result <- db_table %>%
  filter(value > 100) %>%
  group_by(category) %>%
  summarise(mean_value = mean(value))

# View SQL query that will be generated
show_query(result)

# Execute and collect results
final_result <- collect(result)

# Close connection
dbDisconnect(con)

4. Data Visualization Tricks

4.1 ggplot2 Essentials

Basic ggplot2 Structure

library(ggplot2)

# Basic template
# ggplot(data, aes(x, y, ...)) + geom_*() + ...

# Scatter plot
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()

# With color
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  labs(title = "Fuel Efficiency vs Weight",
       x = "Weight (1000 lbs)",
       y = "Miles Per Gallon",
       color = "Cylinders")

# Line plot
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line(color = "blue", size = 1) +
  theme_minimal()

# Bar plot
ggplot(mtcars, aes(x = factor(cyl))) +
  geom_bar(fill = "steelblue") +
  labs(title = "Count by Cylinder", x = "Cylinders", y = "Count")

# Histogram
ggplot(mtcars, aes(x = mpg)) +
  geom_histogram(bins = 10, fill = "darkgreen", color = "white") +
  theme_classic()

# Box plot
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
  geom_boxplot(fill = "lightblue") +
  geom_jitter(width = 0.2, alpha = 0.3)

Advanced ggplot2 Tricks

library(dplyr)

# Multiple geoms
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point(aes(color = factor(cyl)), size = 3) +
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  theme_minimal() +
  labs(title = "MPG vs Weight with Linear Trend")

# Faceting
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  facet_wrap(~ cyl) +
  theme_bw()

# Custom themes
custom_theme <- theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 12),
    legend.position = "bottom"
  )

ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  custom_theme

# Color palettes
library(viridis)
ggplot(mtcars, aes(x = wt, y = mpg, color = hp)) +
  geom_point(size = 4) +
  scale_color_viridis_c() +
  theme_dark()

# Annotations
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  annotate("text", x = 4, y = 30, label = "Annotation", size = 5) +
  annotate("rect", xmin = 3, xmax = 4, ymin = 25, ymax = 30, 
           alpha = 0.2, fill = "red")

# Coordinates
ggplot(mtcars, aes(x = factor(cyl), fill = factor(gear))) +
  geom_bar() +
  coord_polar()  # Pie-like chart

# Scales
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  scale_x_continuous(breaks = seq(0, 6, 1)) +
  scale_y_continuous(trans = "log10")

Quick Plotting Tips

# Ensure the output directory exists
if (!dir.exists("output")) {
  dir.create("output", recursive = TRUE)
}

# Save the last plot
ggsave("output/my_plot.png", width = 8, height = 6, dpi = 300)

# Save a specific plot
p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
ggsave("output/specific_plot.png", plot = p, width = 10, height = 6)

# Combine plots using patchwork
library(patchwork)

p1 <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
p2 <- ggplot(mtcars, aes(x = hp, y = mpg)) + geom_point()
p3 <- ggplot(mtcars, aes(x = factor(cyl))) + geom_bar()

# Side by side
p1 + p2

# Stacked
p1 / p2

# Complex layout
(p1 | p2) / p3

4.2 Interactive Visualizations

plotly

library(plotly)

# Convert ggplot to plotly
p <- ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3)

ggplotly(p)

# Native plotly
plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", mode = "markers",
        color = ~factor(cyl), size = ~hp)

# 3D scatter
plot_ly(mtcars, x = ~wt, y = ~hp, z = ~mpg, 
        type = "scatter3d", mode = "markers",
        color = ~factor(cyl))

Other Visualization Packages

# highcharter
library(highcharter)
hchart(mtcars, "scatter", hcaes(x = wt, y = mpg, group = cyl))

# echarts4r
library(echarts4r)
mtcars %>%
  e_charts(wt) %>%
  e_scatter(mpg) %>%
  e_title("MPG vs Weight")

# ggvis (interactive ggplot-like)
library(ggvis)
mtcars %>%
  ggvis(~wt, ~mpg) %>%
  layer_points(fill = ~factor(cyl))

5. Time Series Data Handling

5.1 Time Series Basics

Lubridate for Date Manipulation

library(lubridate)

# Parsing dates
ymd("2023-01-15")
## [1] "2023-01-15"
mdy("01/15/2023")
## [1] "2023-01-15"
dmy("15-01-2023")
## [1] "2023-01-15"
# Date-time
ymd_hms("2023-01-15 14:30:00")
## [1] "2023-01-15 14:30:00 UTC"
# Extract components
date <- ymd("2023-01-15")
year(date)
## [1] 2023
month(date)
## [1] 1
day(date)
## [1] 15
wday(date, label = TRUE)
## [1] Sun
## Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat
quarter(date)
## [1] 1
# Date arithmetic
date + days(10)
## [1] "2023-01-25"
date + months(2)
## [1] "2023-03-15"
date + years(1)
## [1] "2024-01-15"
# Intervals
interval(ymd("2023-01-01"), ymd("2023-12-31"))
## [1] 2023-01-01 UTC--2023-12-31 UTC
# Durations
duration(5, "days")
## [1] "432000s (~5 days)"
ddays(5)
## [1] "432000s (~5 days)"
dweeks(2)
## [1] "1209600s (~2 weeks)"
# Periods
period(5, "days")
## [1] "5d 0H 0M 0S"
days(5)
## [1] "5d 0H 0M 0S"
weeks(2)
## [1] "14d 0H 0M 0S"
# Time zones
with_tz(now(), "America/New_York")
## [1] "2026-02-08 18:01:21 EST"
force_tz(now(), "America/New_York")
## [1] "2026-02-08 23:01:21 EST"
# Floor/ceiling dates
floor_date(date, "month")
## [1] "2023-01-01"
ceiling_date(date, "month")
## [1] "2023-02-01"
round_date(date, "month")
## [1] "2023-01-01"

5.2 Time Series Visualization

library(ggplot2)
library(dygraphs)

# --------------------------
# Create example ts data
# --------------------------
set.seed(123)
dates <- seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "day")
values <- cumsum(rnorm(length(dates)))

# Base R ts object for the first year
ts_data <- ts(values[1:365], start = c(2020, 1), frequency = 365)


library(zoo)

zoo_ts <- zoo(ts_data)
ts_df <- data.frame(
  date = index(zoo_ts),
  value = coredata(zoo_ts)
)

library(ggplot2)
ggplot(ts_df, aes(x = date, y = value)) +
  geom_line() +
  theme_minimal() +
  labs(title = "Time Series Plot")

5.3 Time Series Analysis

Decomposition

# Create seasonal time series
monthly_ts <- ts(rnorm(120) + 1:120/10 + sin(2*pi*(1:120)/12), 
                 start = c(2015, 1), frequency = 12)

# Decompose
decomposed <- decompose(monthly_ts)
plot(decomposed)

# STL decomposition (more robust)
stl_result <- stl(monthly_ts, s.window = "periodic")
plot(stl_result)

Forecasting Basics

library(forecast)

# Auto ARIMA
fit <- auto.arima(monthly_ts)
forecasted <- forecast(fit, h = 12)  # 12 months ahead
plot(forecasted)

# Exponential smoothing
fit_ets <- ets(monthly_ts)
forecasted_ets <- forecast(fit_ets, h = 12)
plot(forecasted_ets)

# Accuracy
accuracy(fit)

6. Geospatial Data Handling Tips

6.1 Quick Geospatial Tricks

Essential sf Operations

# Load required libraries
library(sf)
library(dplyr)
library(spData)  # example spatial datasets

# --------------------------
# Use built-in example dataset
# --------------------------
sf_data <- world          # 'world' dataset from spData
sf_data <- st_as_sf(sf_data)  # ensure it's an sf object

# Quick plot
plot(st_geometry(sf_data))

# --------------------------
# Buffer example (in meters if projected)
# --------------------------
# Transform to a projected CRS for meters
sf_proj <- st_transform(sf_data, crs = 3857)
buffered <- st_buffer(sf_proj, dist = 1000000)  # 1,000 km buffer

# Plot buffered geometry
plot(st_geometry(buffered))

# --------------------------
# Intersection example
# --------------------------
# Let's intersect two countries as example
other_sf <- sf_data %>% filter(name_long %in% c("France", "Germany"))
overlap <- st_intersection(other_sf, other_sf)  # self-intersection just as demo
plot(st_geometry(overlap), col = "red")

# --------------------------
# Distance matrix
# --------------------------
distances <- st_distance(sf_proj[1:5, ])  # only first 5 for simplicity
print(distances)

# --------------------------
# Centroid
# --------------------------
centroids <- st_centroid(sf_proj)
plot(st_geometry(centroids), col = "blue", pch = 16, add = TRUE)

# --------------------------
# Area (in projected CRS!)
# --------------------------
areas <- st_area(sf_proj)
head(areas)

# --------------------------
# Nearest feature
# --------------------------
# Example: find nearest neighbor for first 5 countries
nearest <- st_nearest_feature(sf_proj[1:5, ], sf_proj[6:10, ])
print(nearest)

Quick Mapping

library(mapview)
library(leaflet)

# Instant interactive map
mapview(sf_data)



# Leaflet
leaflet(sf_data) %>%
  addTiles() %>%
  addPolygons(fillColor = "blue", weight = 1)

6.2 Raster Tips

# Load libraries
library(terra)
library(sf)
library(dplyr)

# ---------------------
# Load example raster
# ---------------------
# Get the path for the included example raster file
elev_path <- system.file("raster/elev.tif", package = "spData")

# Check that file exists
if (elev_path == "") {
  stop("Example raster not found – install 'spData' and ensure it is up to date.")
}

# Read raster as terra SpatRaster
r <- rast(elev_path)

# Quick plot
plot(r, main = "Example Elevation Raster")

# ---------------------
# Extract raster values at points
# ---------------------
points_sf <- st_as_sf(
  data.frame(lon = c(-0.1, 2.3), lat = c(51.5, 48.8)),
  coords = c("lon", "lat"),
  crs = 4326
)

# Convert sf to terra vector
points_vect <- vect(points_sf)

# Extract raster values at those points
extracted <- terra::extract(r, points_vect)
print(extracted)

# ---------------------
# Raster calculator
# ---------------------
r2 <- r * 2 + 100
plot(r2, main = "Raster Calculator")

# ---------------------
# Aggregate (coarser resolution)
# ---------------------
r_coarse <- aggregate(r, fact = 5, fun = mean)
plot(r_coarse, main = "Aggregated Raster")

# ---------------------
# Resample raster
# ---------------------
r_resample <- resample(r, r_coarse, method = "bilinear")
plot(r_resample, main = "Resampled Raster")

7. Shiny Apps Basics

7.1 Shiny App Structure

Minimal Shiny App

library(shiny)

# UI
ui <- fluidPage(
  titlePanel("My First Shiny App"),
  
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins", "Number of bins:", 
                  min = 5, max = 50, value = 30)
    ),
    
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

# Server
server <- function(input, output) {
  output$distPlot <- renderPlot({
    x <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = "darkgray", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times")
  })
}

# Run app
shinyApp(ui = ui, server = server)

Input/Output Widgets

# UI inputs
sliderInput("slider", "Slider:", min = 0, max = 100, value = 50)
numericInput("number", "Number:", value = 10)
textInput("text", "Text:", value = "Enter text")
selectInput("select", "Select:", choices = c("A", "B", "C"))
checkboxInput("checkbox", "Checkbox", value = TRUE)
dateInput("date", "Date:")
fileInput("file", "Choose file")

# Outputs
plotOutput("plot")
tableOutput("table")
textOutput("text")
verbatimTextOutput("code")
uiOutput("ui")

7.2 Reactive Programming

Basic Reactivity

server <- function(input, output) {
  
  # Reactive expression (computed once per change)
  data_filtered <- reactive({
    mtcars %>% filter(cyl == input$cyl)
  })
  
  # Use reactive data
  output$plot <- renderPlot({
    ggplot(data_filtered(), aes(x = wt, y = mpg)) + geom_point()
  })
  
  output$table <- renderTable({
    data_filtered()
  })
  
  # Observe (side effects only)
  observe({
    print(paste("Cylinders selected:", input$cyl))
  })
  
  # observeEvent (react to specific input)
  observeEvent(input$button, {
    showModal(modalDialog("Button clicked!"))
  })
}

7.3 Shiny Dashboard

library(shinydashboard)

ui <- dashboardPage(
  dashboardHeader(title = "My Dashboard"),
  
  dashboardSidebar(
    sidebarMenu(
      menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
      menuItem("Data", tabName = "data", icon = icon("table"))
    )
  ),
  
  dashboardBody(
    tabItems(
      tabItem(tabName = "dashboard",
              fluidRow(
                valueBoxOutput("value1"),
                valueBoxOutput("value2")
              ),
              fluidRow(
                box(plotOutput("plot1"), width = 6),
                box(plotOutput("plot2"), width = 6)
              )
      ),
      
      tabItem(tabName = "data",
              fluidRow(
                box(tableOutput("table"), width = 12)
              )
      )
    )
  )
)

server <- function(input, output) {
  output$value1 <- renderValueBox({
    valueBox(nrow(mtcars), "Total Cars", icon = icon("car"))
  })
  
  output$plot1 <- renderPlot({
    ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
  })
  
  output$table <- renderTable({
    head(mtcars)
  })
}

shinyApp(ui, server)

7.4 Shiny Tips and Tricks

# 1. Use isolate() to prevent reactivity
output$plot <- renderPlot({
  # Only reacts to input$update, not input$bins
  input$update
  isolate({
    hist(rnorm(100), breaks = input$bins)
  })
})

# 2. Use eventReactive() for better control
data_processed <- eventReactive(input$go_button, {
  # Only runs when button is clicked
  process_data(input$data)
})

# 3. Use req() to prevent errors
output$plot <- renderPlot({
  req(input$file)  # Don't run if file not uploaded
  data <- read.csv(input$file$datapath)
  plot(data)
})

# 4. Use validate() for custom error messages
output$plot <- renderPlot({
  validate(
    need(input$data != "", "Please upload data"),
    need(nrow(input$data) > 10, "Need at least 10 rows")
  )
  plot(input$data)
})

# 5. Use updateInput() to change inputs from server
observeEvent(input$reset, {
  updateSliderInput(session, "bins", value = 30)
  updateTextInput(session, "text", value = "")
})

# 6. Use downloadHandler for file downloads
output$download <- downloadHandler(
  filename = function() {
    paste("data-", Sys.Date(), ".csv", sep = "")
  },
  content = function(file) {
    write.csv(data(), file, row.names = FALSE)
  }
)

# 7. Use shinyjs for JavaScript interactions
library(shinyjs)
useShinyjs()  # In UI
onclick("button", alert("Clicked!"))
hide("element")
show("element")

8. Performance Optimization Tips

8.1 Code Profiling

# Profile code execution time
library(profvis)

profvis({
  # Your code here
  x <- numeric(1000)
  for(i in 1:1000) {
    x[i] <- i^2
  }
})

# Benchmark alternatives
library(microbenchmark)

microbenchmark(
  loop = {
    x <- numeric(1000)
    for(i in 1:1000) x[i] <- i^2
  },
  vectorized = {
    x <- (1:1000)^2
  },
  times = 100
)

8.2 Vectorization Tricks

# Always prefer vectorized operations

# BAD - Loop
result <- numeric(1000)
for(i in 1:1000) {
  result[i] <- sqrt(i)
}

# GOOD - Vectorized
result <- sqrt(1:1000)

# Use apply family
mat <- matrix(1:12, 3, 4)
apply(mat, 2, sum)  # Column sums
## [1]  6 15 24 33
colSums(mat)  # Even faster!
## [1]  6 15 24 33
# Use ifelse instead of if-else in loops
x <- 1:10
ifelse(x > 5, "High", "Low")
##  [1] "Low"  "Low"  "Low"  "Low"  "Low"  "High" "High" "High" "High" "High"

8.3 Compilation

# Use compiler package
library(compiler)

# Compile function
my_func <- function(n) {
  result <- 0
  for(i in 1:n) result <- result + i
  result
}

my_func_compiled <- cmpfun(my_func)

# Test speed
microbenchmark(
  original = my_func(10000),
  compiled = my_func_compiled(10000),
  times = 100
)

9. Best Practices Summary

9.1 Project Organization

my_project/
│
├── README.md                 # Project overview
├── my_project.Rproj         # RStudio project file
│
├── data/
│   ├── raw/                 # Original, immutable data
│   └── processed/           # Cleaned, processed data
│
├── scripts/
│   ├── 01_data_import.R
│   ├── 02_data_cleaning.R
│   ├── 03_analysis.R
│   └── 04_visualization.R
│
├── output/
│   ├── figures/
│   └── tables/
│
├── reports/
│   └── analysis_report.Rmd
│
└── functions/
    └── helper_functions.R

9.2 Code Style Guide

# Use styler package to auto-format code
library(styler)
style_file("script.R")
style_dir("scripts/")

# Use lintr to check code quality
library(lintr)
lint("script.R")

# Naming conventions:
# - snake_case for variables and functions
# - UPPERCASE for constants
# - Meaningful names

# Good spacing
x <- 5 + 3  # GOOD
x<-5+3      # BAD

# Comment your code
# Calculate average age of customers
mean_age <- mean(customer_data$age)

# Use functions for repeated code
calculate_metrics <- function(data) {
  # Your code
}

9.3 Version Control

# Initialize git repository
git init

# Create .gitignore
# Add: *.RData, *.Rhistory, .Rproj.user/, data/

# Commit changes
git add .
git commit -m "Initial commit"

# Connect to GitHub
git remote add origin https://github.com/username/repo.git
git push -u origin main

10. Essential R Packages Cheat Sheet

10.1 Data Manipulation

Package Purpose Key Functions
dplyr Data manipulation select(), filter(), mutate(), summarise(), group_by()
tidyr Data reshaping pivot_longer(), pivot_wider(), separate(), unite()
data.table Fast data manipulation [i, j, by], :=, setkey()
stringr String manipulation str_detect(), str_replace(), str_extract()
lubridate Date/time handling ymd(), floor_date(), interval()

10.2 Visualization

Package Purpose Key Functions
ggplot2 Static plots ggplot(), geom_*(), theme_*()
plotly Interactive plots plot_ly(), ggplotly()
leaflet Interactive maps leaflet(), addTiles(), addMarkers()
gganimate Animated plots transition_*(), animate()

10.3 Modeling & Stats

Package Purpose Key Functions
caret Machine learning train(), predict(), confusionMatrix()
randomForest Random forests randomForest()
glmnet Regularized regression glmnet(), cv.glmnet()
forecast Time series forecasting auto.arima(), ets(), forecast()

10.4 Big Data

Package Purpose Key Functions
data.table Fast operations All operations
arrow Large files read_parquet(), open_dataset()
sparklyr Spark interface spark_connect(), spark_read_*()
disk.frame Disk-based operations csv_to_disk.frame()

11. Additional Resources

11.1 Essential Books

  1. “R for Data Science” by Hadley Wickham & Garrett Grolemund
  2. “Advanced R” by Hadley Wickham
  3. “R Graphics Cookbook” by Winston Chang
    • Comprehensive ggplot2 guide
  4. “Geocomputation with R” by Robin Lovelace et al.
  5. “Forecasting: Principles and Practice” by Rob Hyndman

11.2 Online Resources

Learning Platforms

Communities

11.3 Staying Updated

# Subscribe to R Weekly newsletter
# https://rweekly.org/

# Follow R developers on Twitter
# @hadleywickham, @JennyBryan, @WeAreRLadies

# Attend conferences
# useR!, rstudio::conf, satRdays

# Join local R user groups
# https://www.meetup.com/topics/r-project-for-statistical-computing/

# Read R Journal
# https://journal.r-project.org/

12. Practice Exercises

Exercise 1: Data Manipulation

# Task: Load mtcars, create new columns, summarize by groups
# 1. Calculate mpg per cylinder ratio
# 2. Categorize cars as "efficient" (mpg > 20) or "inefficient"
# 3. Calculate mean hp and mean mpg by cylinder and efficiency category
# 4. Sort results by mean_hp descending

# Your solution here

Exercise 2: Visualization

# Task: Create a comprehensive visualization
# 1. Use mtcars dataset
# 2. Create scatter plot of mpg vs wt
# 3. Color by number of cylinders
# 4. Add smoothing line
# 5. Facet by transmission type (am)
# 6. Apply custom theme
# 7. Add informative labels

# Your solution here

Exercise 3: Time Series

# Task: Analyze AirPassengers dataset
# 1. Decompose the time series
# 2. Calculate 12-month moving average
# 3. Plot original vs smoothed series
# 4. Forecast 24 months ahead
# 5. Visualize forecast with confidence intervals

# Your solution here

Exercise 4: Functions

# Task: Write a flexible summary function
# Create a function that:
# 1. Takes a data frame and column name
# 2. Returns mean, median, sd, min, max, and number of NAs
# 3. Handles non-numeric columns gracefully
# 4. Optionally removes outliers before calculation

# Your solution here

Appendix: Session Information

# System information
sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows Server 2022 x64 (build 20348)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=English_United Kingdom.utf8 
## [2] LC_CTYPE=English_United Kingdom.utf8   
## [3] LC_MONETARY=English_United Kingdom.utf8
## [4] LC_NUMERIC=C                           
## [5] LC_TIME=English_United Kingdom.utf8    
## 
## time zone: Europe/London
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] zoo_1.8-14        dygraphs_1.1.1.6  lubridate_1.9.4   patchwork_1.3.2  
##  [5] viridis_0.6.5     viridisLite_0.4.2 ggplot2_4.0.2     data.table_1.17.8
##  [9] bit64_4.6.0-1     bit_4.6.0         stringr_1.5.2     tidyr_1.3.2      
## [13] MASS_7.3-65       dplyr_1.1.4       conflicted_1.2.0 
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10        utf8_1.2.6         generics_0.1.4     stringi_1.8.7     
##  [5] lattice_0.22-7     digest_0.6.37      magrittr_2.0.4     timechange_0.3.0  
##  [9] evaluate_1.0.5     grid_4.5.1         RColorBrewer_1.1-3 fastmap_1.2.0     
## [13] jsonlite_2.0.0     Matrix_1.7-3       gridExtra_2.3      mgcv_1.9-3        
## [17] purrr_1.1.0        scales_1.4.0       textshaping_1.0.4  jquerylib_0.1.4   
## [21] cli_3.6.5          rlang_1.1.7        splines_4.5.1      withr_3.0.2       
## [25] cachem_1.1.0       yaml_2.3.10        tools_4.5.1        memoise_2.0.1     
## [29] vctrs_0.7.1        R6_2.6.1           lifecycle_1.0.4    htmlwidgets_1.6.4 
## [33] ragg_1.5.0         pkgconfig_2.0.3    pillar_1.11.1      bslib_0.9.0       
## [37] gtable_0.3.6       glue_1.8.0         systemfonts_1.3.1  xfun_0.53         
## [41] tibble_3.3.0       tidyselect_1.2.1   rstudioapi_0.17.1  knitr_1.50        
## [45] dichromat_2.0-0.1  farver_2.1.2       htmltools_0.5.8.1  nlme_3.1-168      
## [49] rmarkdown_2.30     labeling_0.4.3     compiler_4.5.1     S7_0.2.0
# Package versions
installed_packages <- installed.packages()[, c("Package", "Version")]
key_packages <- c("dplyr", "ggplot2", "tidyr", "sf", "terra", 
                  "shiny", "data.table", "lubridate", "forecast")
installed_packages[installed_packages[, "Package"] %in% key_packages, ]
##            Package      Version 
## data.table "data.table" "1.17.8"
## dplyr      "dplyr"      "1.1.4" 
## forecast   "forecast"   "8.24.0"
## ggplot2    "ggplot2"    "4.0.2" 
## lubridate  "lubridate"  "1.9.4" 
## sf         "sf"         "1.0-21"
## shiny      "shiny"      "1.11.1"
## terra      "terra"      "1.8-70"
## tidyr      "tidyr"      "1.3.2"

Quick Reference Card

Most Used Functions

# Data Import/Export
read_csv()        # Import CSV
write_csv()       # Export CSV
readRDS()         # Import RDS
saveRDS()         # Export RDS

# Data Manipulation
select()          # Select columns
filter()          # Filter rows
mutate()          # Create/modify columns
summarise()       # Aggregate
group_by()        # Group data
arrange()         # Sort rows
left_join()       # Join data

# Data Cleaning
na.omit()         # Remove NAs
replace_na()      # Replace NAs
distinct()        # Remove duplicates
str_trim()        # Trim whitespace

# Visualization
ggplot()          # Initialize plot
geom_point()      # Scatter plot
geom_line()       # Line plot
geom_bar()        # Bar plot
facet_wrap()      # Faceting
ggsave()          # Save plot

# Statistics
mean()            # Mean
median()          # Median
sd()              # Standard deviation
cor()             # Correlation
lm()              # Linear model
summary()         # Summary statistics

# Time Series
ts()              # Create time series
decompose()       # Decompose
lag()             # Lag values
diff()            # Difference

# Geospatial
st_read()         # Read spatial data
st_transform()    # Transform CRS
st_buffer()       # Buffer
st_intersection() # Intersection

This material is part of the training program by The National Centre for Research Methods © NCRM authored by Dr Somnath Chaudhuri (University of Southampton). Content is under a CC BY‑style permissive license and can be freely used for educational purposes with proper attribution.

LS0tDQp0aXRsZTogIlIgUHJvZ3JhbW1pbmc6IENvbXBsZXRlIFRyYWluaW5nIE1hbnVhbCB3aXRoIFRpcHMgJiBUcmlja3MiDQphdXRob3I6ICJTb21uYXRoIENoYXVkaHVyaSwgVW5pdmVyc2l0eSBvZiBTb3V0aGFtcHRvbiwgVUsiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGNvc21vDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNA0KICAgIGdlb21ldHJ5OiBtYXJnaW49MWluDQogICAgZm9udHNpemU6IDExcHQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyA9IFRSVUUsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICBmaWcud2lkdGggPSAxMCwNCiAgZmlnLmhlaWdodCA9IDYsDQogIGRwaSA9IDMwMCwNCiAgY2FjaGUgPSBGQUxTRQ0KKQ0KbGlicmFyeShjb25mbGljdGVkKQ0KY29uZmxpY3RfcHJlZmVyKCJzZWxlY3QiLCAiZHBseXIiKQ0KY29uZmxpY3RfcHJlZmVyKCJmaWx0ZXIiLCAiZHBseXIiKQ0KY29uZmxpY3RzX3ByZWZlcihiYXNlOjpgOmApDQpjb25mbGljdHNfcHJlZmVyKGx1YnJpZGF0ZTo6eWVhcikNCmNvbmZsaWN0c19wcmVmZXIobHVicmlkYXRlOjptb250aCkNCmNvbmZsaWN0c19wcmVmZXIobHVicmlkYXRlOjp3ZGF5KQ0KY29uZmxpY3RzX3ByZWZlcihsdWJyaWRhdGU6OnF1YXJ0ZXIpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBjb21wcmVoZW5zaXZlIHRyYWluaW5nIG1hbnVhbCBwcm92aWRlcyBlc3NlbnRpYWwgdGlwcywgdHJpY2tzLCBzaG9ydGN1dHMsIGFuZCBiZXN0IHByYWN0aWNlcyBmb3IgUiBwcm9ncmFtbWluZyBhY3Jvc3MgdmFyaW91cyBkb21haW5zLiBXaGV0aGVyIHlvdSdyZSBhIGJlZ2lubmVyIG9yIGludGVybWVkaWF0ZSB1c2VyLCB0aGlzIGd1aWRlIHdpbGwgaGVscCB5b3Ugd3JpdGUgYmV0dGVyLCBmYXN0ZXIsIGFuZCBtb3JlIGVmZmljaWVudCBSIGNvZGUuDQoNCiMjIFdoYXQgWW91J2xsIExlYXJuDQoNCjEuICoqQmFzaWMgUioqOiBGdW5kYW1lbnRhbHMsIHNob3J0Y3V0cywgYW5kIHByb2R1Y3Rpdml0eSB0aXBzDQoyLiAqKkRhdGEgSGFuZGxpbmcqKjogSW1wb3J0LCBleHBvcnQsIG1hbmlwdWxhdGlvbiwgYW5kIGNsZWFuaW5nDQozLiAqKkJpZyBEYXRhKio6IFRlY2huaXF1ZXMgZm9yIGhhbmRsaW5nIGxhcmdlIGRhdGFzZXRzIGVmZmljaWVudGx5DQo0LiAqKkRhdGEgVmlzdWFsaXphdGlvbioqOiBDcmVhdGluZyBpbXBhY3RmdWwgZ3JhcGhpY3MNCjUuICoqVGltZSBTZXJpZXMqKjogVGVtcG9yYWwgZGF0YSBhbmFseXNpcyBhbmQgZm9yZWNhc3RpbmcNCjYuICoqR2Vvc3BhdGlhbCBEYXRhKio6IE1hcHBpbmcgYW5kIHNwYXRpYWwgYW5hbHlzaXMNCjcuICoqU2hpbnkgQXBwcyoqOiBCdWlsZGluZyBpbnRlcmFjdGl2ZSB3ZWIgYXBwbGljYXRpb25zDQoNCi0tLQ0KDQojIDEuIEJhc2ljIFI6IEVzc2VudGlhbCBUaXBzIGFuZCBUcmlja3MNCg0KIyMgMS4xIEdldHRpbmcgU3RhcnRlZDogSW5pdGlhbCBTZXR1cA0KDQojIyMgUlN0dWRpbyBLZXlib2FyZCBTaG9ydGN1dHMgKE11c3QgS25vdyEpDQoNCmBgYHtyIHNob3J0Y3V0c19yZWZlcmVuY2UsIGV2YWw9RkFMU0V9DQojIEVTU0VOVElBTCBLRVlCT0FSRCBTSE9SVENVVFMgKFdvcmtzIG9uIFdpbmRvd3MvTWFjKQ0KIyANCiMgQ29kZSBFeGVjdXRpb246DQojIEN0cmwvQ21kICsgRW50ZXIgICAgICAgIC0gUnVuIGN1cnJlbnQgbGluZSBvciBzZWxlY3Rpb24NCiMgQ3RybC9DbWQgKyBTaGlmdCArIEVudGVyIC0gUnVuIGVudGlyZSBzY3JpcHQNCiMgQ3RybC9DbWQgKyBTaGlmdCArIFMgICAgLSBTb3VyY2UgZW50aXJlIHNjcmlwdA0KIyANCiMgQ29kZSBFZGl0aW5nOg0KIyBDdHJsL0NtZCArIFNoaWZ0ICsgQyAgICAtIENvbW1lbnQvdW5jb21tZW50IGxpbmVzDQojIEN0cmwvQ21kICsgSSAgICAgICAgICAgIC0gUmUtaW5kZW50IGNvZGUNCiMgQ3RybC9DbWQgKyBTaGlmdCArIEEgICAgLSBSZWZvcm1hdCBjb2RlDQojIEFsdCArIC0gICAgICAgICAgICAgICAgIC0gSW5zZXJ0IGFzc2lnbm1lbnQgb3BlcmF0b3IgPC0NCiMgQ3RybC9DbWQgKyBTaGlmdCArIE0gICAgLSBJbnNlcnQgcGlwZSBvcGVyYXRvciAlPiUNCiMgDQojIE5hdmlnYXRpb246DQojIEN0cmwvQ21kICsgMSAgICAgICAgICAgIC0gTW92ZSBjdXJzb3IgdG8gc291cmNlIGVkaXRvcg0KIyBDdHJsL0NtZCArIDIgICAgICAgICAgICAtIE1vdmUgY3Vyc29yIHRvIGNvbnNvbGUNCiMgQ3RybC9DbWQgKyBTaGlmdCArIEYgICAgLSBGaW5kIGluIGZpbGVzDQojIEN0cmwvQ21kICsgRiAgICAgICAgICAgIC0gRmluZC9yZXBsYWNlIGluIGN1cnJlbnQgZmlsZQ0KIyANCiMgQ29kZSBDb21wbGV0aW9uOg0KIyBUYWIgICAgICAgICAgICAgICAgICAgICAtIEF1dG8tY29tcGxldGUNCiMgQ3RybC9DbWQgKyBTcGFjZSAgICAgICAgLSBTaG93IGZ1bmN0aW9uIGFyZ3VtZW50cw0KIyBGMSAgICAgICAgICAgICAgICAgICAgICAtIE9wZW4gaGVscCBmb3IgZnVuY3Rpb24gdW5kZXIgY3Vyc29yDQojIA0KIyBTZXNzaW9uIE1hbmFnZW1lbnQ6DQojIEN0cmwvQ21kICsgU2hpZnQgKyBGMTAgIC0gUmVzdGFydCBSIHNlc3Npb24NCiMgQ3RybC9DbWQgKyBMICAgICAgICAgICAgLSBDbGVhciBjb25zb2xlDQpgYGANCg0KIyMjIFNldHRpbmcgVXAgWW91ciBSIEVudmlyb25tZW50DQoNCmBgYHtyIGVudmlyb25tZW50X3NldHVwLCBldmFsPUZBTFNFfQ0KIyAxLiBTZXQgd29ya2luZyBkaXJlY3RvcnkgKERPIFRISVMgRklSU1QhKQ0Kc2V0d2QoIn4vUl9Qcm9qZWN0cy9NeVByb2plY3QiKSAgIyBMaW51eC9NYWMNCnNldHdkKCJDOi9Vc2Vycy9Zb3VyTmFtZS9SX1Byb2plY3RzL015UHJvamVjdCIpICAjIFdpbmRvd3MNCg0KIyBCZXR0ZXI6IFVzZSBSU3R1ZGlvIFByb2plY3RzICguUnByb2ogZmlsZXMpIC0gdGhleSBhdXRvLXNldCB3b3JraW5nIGRpcmVjdG9yeSENCg0KIyAyLiBDaGVjayB5b3VyIGN1cnJlbnQgZGlyZWN0b3J5DQpnZXR3ZCgpDQoNCiMgMy4gTGlzdCBmaWxlcyBpbiBkaXJlY3RvcnkNCmxpc3QuZmlsZXMoKQ0KZGlyKCkgICMgU2FtZSBhcyBsaXN0LmZpbGVzKCkNCg0KIyA0LiBDcmVhdGUgcHJvamVjdCBzdHJ1Y3R1cmUNCmRpci5jcmVhdGUoImRhdGEiKQ0KZGlyLmNyZWF0ZSgic2NyaXB0cyIpDQpkaXIuY3JlYXRlKCJvdXRwdXQiKQ0KZGlyLmNyZWF0ZSgiZmlndXJlcyIpDQoNCiMgNS4gU2V0IGdsb2JhbCBvcHRpb25zDQpvcHRpb25zKA0KICBzY2lwZW4gPSA5OTksICAgICAgICAgICAgICAjIERpc2FibGUgc2NpZW50aWZpYyBub3RhdGlvbg0KICBkaWdpdHMgPSAzLCAgICAgICAgICAgICAgICAjIE51bWJlciBvZiBkaWdpdHMgdG8gZGlzcGxheQ0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsICAjIERvbid0IGF1dG8tY29udmVydCBzdHJpbmdzIHRvIGZhY3RvcnMNCiAgcmVwb3MgPSAiaHR0cHM6Ly9jcmFuLnJzdHVkaW8uY29tLyIgICMgRGVmYXVsdCBDUkFOIG1pcnJvcg0KKQ0KYGBgDQoNCiMjIDEuMiBCYXNpYyBSIERvcyBhbmQgRG9uJ3RzDQoNCiMjIyAgRE8ncw0KDQpgYGB7ciBiYXNpY19kb3N9DQojICBETzogVXNlIG1lYW5pbmdmdWwgdmFyaWFibGUgbmFtZXMNCmN1c3RvbWVyX2FnZSA8LSBjKDI1LCAzMCwgMzUsIDQwKSAgIyBHT09EDQpjYSA8LSBjKDI1LCAzMCwgMzUsIDQwKSAgICAgICAgICAgICMgQkFEDQoNCiMgIERPOiBVc2UgPC0gZm9yIGFzc2lnbm1lbnQgKG5vdCA9KQ0KeCA8LSA1ICAgICAgICAjIEdPT0QgKFIgY29udmVudGlvbikNCnggPSA1ICAgICAgICAgIyBXb3JrcywgYnV0IG5vdCBwcmVmZXJyZWQNCg0KIyAgRE86IEFkZCBjb21tZW50cyB0byBleHBsYWluIHlvdXIgY29kZQ0KIyBDYWxjdWxhdGUgYXZlcmFnZSBjdXN0b21lciBhZ2UNCm1lYW5fYWdlIDwtIG1lYW4oY3VzdG9tZXJfYWdlKQ0KDQojICBETzogVXNlIGNvbnNpc3RlbnQgbmFtaW5nIGNvbnZlbnRpb24NCiMgQ2hvb3NlIG9uZSBhbmQgc3RpY2sgdG8gaXQ6DQpzbmFrZV9jYXNlX3ZhcmlhYmxlIDwtICJyZWNvbW1lbmRlZCIgICMgc25ha2VfY2FzZSAocmVjb21tZW5kZWQpDQpjYW1lbENhc2VWYXJpYWJsZSA8LSAiYWxzb19nb29kIiAgICAgICMgY2FtZWxDYXNlDQojIFBhc2NhbENhc2VWYXJpYWJsZSA8LSAiZm9yX2Z1bmN0aW9ucyIgICMgUGFzY2FsQ2FzZQ0KDQojICBETzogVmVjdG9yaXplIG9wZXJhdGlvbnMgKGF2b2lkIGxvb3BzIHdoZW4gcG9zc2libGUpDQojIEdPT0QgLSBWZWN0b3JpemVkDQpudW1iZXJzIDwtIDE6MTAwMA0Kc3F1YXJlcyA8LSBudW1iZXJzXjINCg0KIyBCQUQgLSBMb29wIChzbG93ZXIpDQpzcXVhcmVzIDwtIG51bWVyaWMoMTAwMCkNCmZvcihpIGluIDE6MTAwMCkgew0KICBzcXVhcmVzW2ldIDwtIGleMg0KfQ0KDQojICBETzogVXNlIGJ1aWx0LWluIGZ1bmN0aW9ucw0Kc3VtKDE6MTAwKSAgICAgICAgICAgICAgIyBHT09EDQp0b3RhbCA8LSAwOyBmb3IoaSBpbiAxOjEwMCkgdG90YWwgPC0gdG90YWwgKyBpICAjIEJBRA0KDQojICBETzogQ2hlY2sgZGF0YSBzdHJ1Y3R1cmUgcmVndWxhcmx5DQpzdHIobXRjYXJzKSAgICAjIFN0cnVjdHVyZQ0KY2xhc3MobXRjYXJzKSAgIyBPYmplY3QgY2xhc3MNCmRpbShtdGNhcnMpICAgICMgRGltZW5zaW9ucw0KaGVhZChtdGNhcnMpICAgIyBGaXJzdCBmZXcgcm93cw0KYGBgDQoNCiMjIyAgRE9OJ1RzDQoNCmBgYHtyIGJhc2ljX2RvbnRzLCBldmFsPUZBTFNFfQ0KIyAgRE9OJ1Q6IFVzZSBhdHRhY2goKSAtIGl0IGNyZWF0ZXMgY29uZnVzaW9uDQphdHRhY2gobXRjYXJzKSAgIyBCQUQgLSBjcmVhdGVzIGFtYmlndWl0eQ0KbXBnICAgICAgICAgICAgICMgV2hpY2ggbXBnPw0KZGV0YWNoKG10Y2FycykNCg0KIyBJbnN0ZWFkLCB1c2U6DQptdGNhcnMkbXBnICAgICAgIyBHT09EIC0gZXhwbGljaXQNCndpdGgobXRjYXJzLCBtZWFuKG1wZykpICAjIEdPT0QgLSBjbGVhciBzY29wZQ0KDQojICBET04nVDogR3JvdyBvYmplY3RzIGluIGxvb3BzDQpyZXN1bHQgPC0gYygpDQpmb3IoaSBpbiAxOjEwMDApIHsNCiAgcmVzdWx0IDwtIGMocmVzdWx0LCBpXjIpICAjIEJBRCAtIHZlcnkgc2xvdyENCn0NCg0KIyBJbnN0ZWFkLCBwcmUtYWxsb2NhdGU6DQpyZXN1bHQgPC0gbnVtZXJpYygxMDAwKQ0KZm9yKGkgaW4gMToxMDAwKSB7DQogIHJlc3VsdFtpXSA8LSBpXjIgICMgR09PRCAtIG11Y2ggZmFzdGVyDQp9DQoNCiMgIERPTidUOiBVc2UgVCBhbmQgRiBmb3IgVFJVRSBhbmQgRkFMU0UNCnggPC0gVCAgICMgQkFEIC0gVCBhbmQgRiBjYW4gYmUgb3ZlcndyaXR0ZW4hDQp4IDwtIEYgICAjIEJBRA0KDQp4IDwtIFRSVUUgICAjIEdPT0QNCnggPC0gRkFMU0UgICMgR09PRA0KDQojICBET04nVDogRm9yZ2V0IHRvIHNldC5zZWVkKCkgZm9yIHJlcHJvZHVjaWJpbGl0eQ0Kc2FtcGxlKDE6MTAsIDUpICAjIEJBRCAtIGRpZmZlcmVudCByZXN1bHRzIGVhY2ggdGltZQ0KDQpzZXQuc2VlZCgxMjMpDQpzYW1wbGUoMToxMCwgNSkgICMgR09PRCAtIHJlcHJvZHVjaWJsZQ0KDQojICBET04nVDogVXNlID09IGZvciBjb21wYXJpbmcgZmxvYXRpbmcgcG9pbnQgbnVtYmVycw0KMC4xICsgMC4yID09IDAuMyAgIyBSZXR1cm5zIEZBTFNFISAoZmxvYXRpbmcgcG9pbnQgcHJlY2lzaW9uKQ0KDQojIFVzZSBhbGwuZXF1YWwoKSBvciBuZWFyKCkNCmFsbC5lcXVhbCgwLjEgKyAwLjIsIDAuMykgICMgVFJVRQ0KZHBseXI6Om5lYXIoMC4xICsgMC4yLCAwLjMpICAjIFRSVUUNCmBgYA0KDQojIyAxLjMgUGFja2FnZSBNYW5hZ2VtZW50IEJlc3QgUHJhY3RpY2VzDQoNCiMjIyBJbnN0YWxsaW5nIGFuZCBMb2FkaW5nIFBhY2thZ2VzDQoNCmBgYHtyIHBhY2thZ2VfbWFuYWdlbWVudCwgZXZhbD1GQUxTRX0NCiMgIEdPT0Q6IENoZWNrIGlmIHBhY2thZ2UgaXMgaW5zdGFsbGVkIGJlZm9yZSBpbnN0YWxsaW5nDQppZiAoIXJlcXVpcmUoImRwbHlyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQ0KfQ0KDQojICBHT09EOiBJbnN0YWxsIG11bHRpcGxlIHBhY2thZ2VzIGF0IG9uY2UNCnBhY2thZ2VzIDwtIGMoImRwbHlyIiwgImdncGxvdDIiLCAidGlkeXIiLCAicmVhZHIiKQ0KaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlcykNCg0KIyAgR09PRDogVXNlIHBhY21hbiBmb3Igc21hcnQgcGFja2FnZSBsb2FkaW5nDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQoZHBseXIsIGdncGxvdDIsIHRpZHlyLCByZWFkcikgICMgSW5zdGFsbHMgaWYgbmVlZGVkLCB0aGVuIGxvYWRzDQoNCiMgIEdPT0Q6IExvYWQgcGFja2FnZXMgYXQgdGhlIHN0YXJ0IG9mIHlvdXIgc2NyaXB0DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCg0KIyAgQkFEOiBMb2FkaW5nIHBhY2thZ2VzIGluIHRoZSBtaWRkbGUgb2YgeW91ciBzY3JpcHQNCiMgLi4uIG1ha2VzIGl0IGhhcmQgdG8gdHJhY2sgZGVwZW5kZW5jaWVzDQoNCiMgIEdPT0Q6IFVzZSBwYWNrYWdlOjpmdW5jdGlvbigpIGZvciByYXJlIGZ1bmN0aW9uIGNhbGxzDQojIEF2b2lkcyBsb2FkaW5nIGVudGlyZSBwYWNrYWdlDQpjb25mbGljdGVkOjpjb25mbGljdF9wcmVmZXIoImZpbHRlciIsICJkcGx5ciIpDQoNCiMgQ2hlY2sgaW5zdGFsbGVkIHBhY2thZ2VzDQppbnN0YWxsZWQucGFja2FnZXMoKVssIGMoIlBhY2thZ2UiLCAiVmVyc2lvbiIpXQ0KDQojIFVwZGF0ZSBhbGwgcGFja2FnZXMNCnVwZGF0ZS5wYWNrYWdlcyhhc2sgPSBGQUxTRSkNCg0KIyBSZW1vdmUgcGFja2FnZQ0KcmVtb3ZlLnBhY2thZ2VzKCJwYWNrYWdlX25hbWUiKQ0KYGBgDQoNCiMjIyBNYW5hZ2luZyBQYWNrYWdlIENvbmZsaWN0cw0KDQpgYGB7ciBwYWNrYWdlX2NvbmZsaWN0c30NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KE1BU1MpICAjIE1BU1M6OnNlbGVjdCgpIGNvbmZsaWN0cyB3aXRoIGRwbHlyOjpzZWxlY3QoKQ0KDQojICBTT0xVVElPTiAxOiBVc2UgcGFja2FnZSBwcmVmaXgNCiMgTUFTUzo6c2VsZWN0KGlyaXMsIFNwZWNpZXMpDQojIGRwbHlyOjpzZWxlY3QoaXJpcywgU3BlY2llcykNCg0KIyAgU09MVVRJT04gMjogVXNlIGNvbmZsaWN0ZWQgcGFja2FnZQ0KbGlicmFyeShjb25mbGljdGVkKQ0KIyBjb25mbGljdF9wcmVmZXIoInNlbGVjdCIsICJkcGx5ciIpDQojIGNvbmZsaWN0X3ByZWZlcigiZmlsdGVyIiwgImRwbHlyIikNCg0KIyBOb3cgc2VsZWN0KCkgd2lsbCBhbHdheXMgdXNlIGRwbHlyIHZlcnNpb24NCmBgYA0KDQojIyAxLjQgRGF0YSBUeXBlcyBhbmQgU3RydWN0dXJlcw0KDQojIyMgVW5kZXJzdGFuZGluZyBCYXNpYyBEYXRhIFR5cGVzDQoNCmBgYHtyIGRhdGFfdHlwZXN9DQojIE51bWVyaWMNCnggPC0gNDINCmNsYXNzKHgpDQoNCiMgSW50ZWdlciAoZXhwbGljaXRseSkNCnkgPC0gNDJMDQpjbGFzcyh5KQ0KDQojIENoYXJhY3Rlcg0KbmFtZSA8LSAiSm9obiBEb2UiDQpjbGFzcyhuYW1lKQ0KDQojIExvZ2ljYWwNCmlzX2FjdGl2ZSA8LSBUUlVFDQpjbGFzcyhpc19hY3RpdmUpDQoNCiMgRmFjdG9yIChmb3IgY2F0ZWdvcmljYWwgZGF0YSkNCmdlbmRlciA8LSBmYWN0b3IoYygiTSIsICJGIiwgIk0iLCAiRiIpKQ0KY2xhc3MoZ2VuZGVyKQ0KbGV2ZWxzKGdlbmRlcikNCg0KIyBEYXRlDQp0b2RheSA8LSBTeXMuRGF0ZSgpDQpjbGFzcyh0b2RheSkNCg0KIyBQT1NJWGN0IChkYXRlLXRpbWUpDQpub3cgPC0gU3lzLnRpbWUoKQ0KY2xhc3Mobm93KQ0KDQojIENoZWNrIHR5cGUNCnR5cGVvZih4KQ0KbW9kZSh4KQ0KY2xhc3MoeCkNCnN0cih4KQ0KYGBgDQoNCiMjIyBEYXRhIFN0cnVjdHVyZXMNCg0KYGBge3IgZGF0YV9zdHJ1Y3R1cmVzfQ0KIyAxLiBWRUNUT1IgKDEtZGltZW5zaW9uYWwsIHNhbWUgdHlwZSkNCnZlY19udW1lcmljIDwtIGMoMSwgMiwgMywgNCwgNSkNCnZlY19jaGFyYWN0ZXIgPC0gYygiYSIsICJiIiwgImMiKQ0KdmVjX2xvZ2ljYWwgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSkNCg0KIyBOYW1lZCB2ZWN0b3JzDQphZ2VzIDwtIGMoSm9obiA9IDI1LCBKYW5lID0gMzAsIEJvYiA9IDM1KQ0KYWdlc1siSm9obiJdDQoNCiMgMi4gTUFUUklYICgyLWRpbWVuc2lvbmFsLCBzYW1lIHR5cGUpDQptYXQgPC0gbWF0cml4KDE6MTIsIG5yb3cgPSAzLCBuY29sID0gNCkNCm1hdA0KDQojIEFjY2VzcyBlbGVtZW50cw0KbWF0WzIsIDNdICAgICAjIFJvdyAyLCBDb2x1bW4gMw0KbWF0WzIsIF0gICAgICAjIEFsbCBvZiByb3cgMg0KbWF0WywgM10gICAgICAjIEFsbCBvZiBjb2x1bW4gMw0KDQojIDMuIEFSUkFZIChuLWRpbWVuc2lvbmFsLCBzYW1lIHR5cGUpDQphcnIgPC0gYXJyYXkoMToyNCwgZGltID0gYygzLCA0LCAyKSkNCg0KIyA0LiBMSVNUIChjYW4gY29udGFpbiBkaWZmZXJlbnQgdHlwZXMpDQpteV9saXN0IDwtIGxpc3QoDQogIG51bWJlcnMgPSAxOjUsDQogIHRleHQgPSAiaGVsbG8iLA0KICBtYXRyaXggPSBtYXRyaXgoMTo0LCAyLCAyKSwNCiAgbmVzdGVkID0gbGlzdChhID0gMSwgYiA9IDIpDQopDQoNCiMgQWNjZXNzIGxpc3QgZWxlbWVudHMNCm15X2xpc3QkbnVtYmVycw0KbXlfbGlzdFtbMV1dDQpteV9saXN0W1sibnVtYmVycyJdXQ0KDQojIDUuIERBVEEgRlJBTUUgKDJELCBkaWZmZXJlbnQgdHlwZXMgaW4gY29sdW1ucykNCmRmIDwtIGRhdGEuZnJhbWUoDQogIGlkID0gMTo1LA0KICBuYW1lID0gYygiQWxpY2UiLCAiQm9iIiwgIkNoYXJsaWUiLCAiRGF2aWQiLCAiRXZlIiksDQogIGFnZSA9IGMoMjUsIDMwLCAzNSwgNDAsIDQ1KSwNCiAgYWN0aXZlID0gYyhUUlVFLCBUUlVFLCBGQUxTRSwgVFJVRSwgRkFMU0UpDQopDQoNCnN0cihkZikNCmBgYA0KDQojIyMgVHlwZSBDb252ZXJzaW9uIFRyaWNrcw0KDQpgYGB7ciB0eXBlX2NvbnZlcnNpb259DQojIENvZXJjaW9uIGhpZXJhcmNoeTogbG9naWNhbCA8IGludGVnZXIgPCBudW1lcmljIDwgY2hhcmFjdGVyDQoNCiMgQ29udmVydCBiZXR3ZWVuIHR5cGVzDQphcy5udW1lcmljKCI0MiIpDQphcy5jaGFyYWN0ZXIoNDIpDQphcy5sb2dpY2FsKDEpICAjIDAgPSBGQUxTRSwgbm9uLXplcm8gPSBUUlVFDQoNCiMgRmFjdG9yIHRvIG51bWVyaWMgKFRSSUNLWSEpDQpmIDwtIGZhY3RvcihjKCIxMCIsICIyMCIsICIzMCIpKQ0KYXMubnVtZXJpYyhmKSAgIyBXUk9ORyEgUmV0dXJucyAxLCAyLCAzDQphcy5udW1lcmljKGFzLmNoYXJhY3RlcihmKSkgICMgQ09SUkVDVCEgUmV0dXJucyAxMCwgMjAsIDMwDQoNCiMgUXVpY2sgY29udmVyc2lvbiB0YWJsZQ0KY29udmVyc2lvbl9leGFtcGxlcyA8LSBkYXRhLmZyYW1lKA0KICBPcGVyYXRpb24gPSBjKCJTdHJpbmcgdG8gTnVtYmVyIiwgIk51bWJlciB0byBTdHJpbmciLCAiRmFjdG9yIHRvIE51bWVyaWMiKSwNCiAgQ29kZSA9IGMoImFzLm51bWVyaWMoJzQyJykiLCAiYXMuY2hhcmFjdGVyKDQyKSIsICJhcy5udW1lcmljKGFzLmNoYXJhY3RlcihmKSkiKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQpwcmludChjb252ZXJzaW9uX2V4YW1wbGVzKQ0KYGBgDQoNCiMjIDEuNSBDb250cm9sIFN0cnVjdHVyZXMgYW5kIEZ1bmN0aW9ucw0KDQojIyMgQ29uZGl0aW9uYWwgU3RhdGVtZW50cw0KDQpgYGB7ciBjb25kaXRpb25hbHN9DQojIElGLUVMU0UNCnggPC0gMTANCg0KaWYgKHggPiA1KSB7DQogIHByaW50KCJ4IGlzIGdyZWF0ZXIgdGhhbiA1IikNCn0gZWxzZSBpZiAoeCA9PSA1KSB7DQogIHByaW50KCJ4IGVxdWFscyA1IikNCn0gZWxzZSB7DQogIHByaW50KCJ4IGlzIGxlc3MgdGhhbiA1IikNCn0NCg0KIyBWZWN0b3JpemVkIGlmZWxzZSgpDQp2YWx1ZXMgPC0gYygxLCA1LCAxMCwgMTUsIDIwKQ0KY2F0ZWdvcmllcyA8LSBpZmVsc2UodmFsdWVzID4gMTAsICJIaWdoIiwgIkxvdyIpDQpjYXRlZ29yaWVzDQoNCiMgY2FzZV93aGVuKCkgZnJvbSBkcGx5ciAobW9yZSByZWFkYWJsZSBmb3IgbXVsdGlwbGUgY29uZGl0aW9ucykNCmxpYnJhcnkoZHBseXIpDQp2YWx1ZXNfZGYgPC0gZGF0YS5mcmFtZSh2YWx1ZSA9IHZhbHVlcykNCnZhbHVlc19kZiAlPiUNCiAgbXV0YXRlKGNhdGVnb3J5ID0gY2FzZV93aGVuKA0KICAgIHZhbHVlIDwgNSB+ICJWZXJ5IExvdyIsDQogICAgdmFsdWUgPCAxMCB+ICJMb3ciLA0KICAgIHZhbHVlIDwgMTUgfiAiTWVkaXVtIiwNCiAgICBUUlVFIH4gIkhpZ2giDQogICkpDQpgYGANCg0KIyMjIExvb3BzIChXaGVuIFlvdSBOZWVkIFRoZW0pDQoNCmBgYHtyIGxvb3BzfQ0KIyBGT1IgbG9vcA0KZm9yIChpIGluIDE6NSkgew0KICBwcmludChwYXN0ZSgiSXRlcmF0aW9uOiIsIGkpKQ0KfQ0KDQojIFdISUxFIGxvb3ANCmNvdW50IDwtIDENCndoaWxlIChjb3VudCA8PSA1KSB7DQogIHByaW50KHBhc3RlKCJDb3VudDoiLCBjb3VudCkpDQogIGNvdW50IDwtIGNvdW50ICsgMQ0KfQ0KDQojIFJFUEVBVCBsb29wICh1c2Ugd2l0aCBicmVhaykNCmNvdW50IDwtIDENCnJlcGVhdCB7DQogIHByaW50KHBhc3RlKCJDb3VudDoiLCBjb3VudCkpDQogIGNvdW50IDwtIGNvdW50ICsgMQ0KICBpZiAoY291bnQgPiA1KSBicmVhaw0KfQ0KDQojICBCRVRURVI6IFVzZSBhcHBseSBmYW1pbHkgaW5zdGVhZCBvZiBsb29wcw0KIyBhcHBseSgpLCBsYXBwbHkoKSwgc2FwcGx5KCksIG1hcHBseSgpLCB0YXBwbHkoKQ0KDQojIEV4YW1wbGU6IENhbGN1bGF0ZSBtZWFuIG9mIGVhY2ggY29sdW1uDQpkZiA8LSBkYXRhLmZyYW1lKA0KICBhID0gMTo1LA0KICBiID0gNjoxMCwNCiAgYyA9IDExOjE1DQopDQoNCiMgVXNpbmcgbG9vcCAoc2xvd2VyKQ0KbWVhbnMgPC0gbnVtZXJpYyhuY29sKGRmKSkNCmZvciAoaSBpbiAxOm5jb2woZGYpKSB7DQogIG1lYW5zW2ldIDwtIG1lYW4oZGZbLCBpXSkNCn0NCg0KIyBVc2luZyBhcHBseSAoZmFzdGVyLCBjbGVhbmVyKQ0KbWVhbnMgPC0gYXBwbHkoZGYsIDIsIG1lYW4pICAjIDIgPSBjb2x1bW5zDQptZWFucw0KDQojIFVzaW5nIGNvbE1lYW5zIChldmVuIGJldHRlciEpDQpjb2xNZWFucyhkZikNCmBgYA0KDQojIyMgV3JpdGluZyBGdW5jdGlvbnMNCg0KYGBge3IgZnVuY3Rpb25zfQ0KIyBCYXNpYyBmdW5jdGlvbg0KY2FsY3VsYXRlX2JtaSA8LSBmdW5jdGlvbih3ZWlnaHRfa2csIGhlaWdodF9tKSB7DQogIGJtaSA8LSB3ZWlnaHRfa2cgLyAoaGVpZ2h0X21eMikNCiAgcmV0dXJuKGJtaSkNCn0NCg0KY2FsY3VsYXRlX2JtaSg3MCwgMS43NSkNCg0KIyBGdW5jdGlvbiB3aXRoIGRlZmF1bHQgYXJndW1lbnRzDQpncmVldCA8LSBmdW5jdGlvbihuYW1lLCBncmVldGluZyA9ICJIZWxsbyIpIHsNCiAgcGFzdGUoZ3JlZXRpbmcsIG5hbWUpDQp9DQoNCmdyZWV0KCJBbGljZSIpDQpncmVldCgiQm9iIiwgIkhpIikNCg0KIyBGdW5jdGlvbiB3aXRoIG11bHRpcGxlIHJldHVybnMNCnN0YXRpc3RpY3MgPC0gZnVuY3Rpb24oeCkgew0KICByZXN1bHQgPC0gbGlzdCgNCiAgICBtZWFuID0gbWVhbih4KSwNCiAgICBtZWRpYW4gPSBtZWRpYW4oeCksDQogICAgc2QgPSBzZCh4KSwNCiAgICBtaW4gPSBtaW4oeCksDQogICAgbWF4ID0gbWF4KHgpDQogICkNCiAgcmV0dXJuKHJlc3VsdCkNCn0NCg0Kc3RhdHMgPC0gc3RhdGlzdGljcygxOjEwMCkNCnN0YXRzJG1lYW4NCg0KIyBBbm9ueW1vdXMgZnVuY3Rpb25zIChsYW1iZGEpDQpzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSB4XjIpDQoNCiMgIE5FVzogUGlwZS1mcmllbmRseSBmdW5jdGlvbnMgd2l0aCB7fQ0KbGlicmFyeShkcGx5cikNCm10Y2FycyAlPiUNCiAgew0KICAgIGRhdGEuZnJhbWUoDQogICAgICBtZWFuX21wZyA9IG1lYW4oLiRtcGcpLA0KICAgICAgbWVhbl9ocCA9IG1lYW4oLiRocCkNCiAgICApDQogIH0NCmBgYA0KDQojIyMgRGVidWdnaW5nIFRpcHMNCg0KYGBge3IgZGVidWdnaW5nLCBldmFsPUZBTFNFfQ0KIyBQcmludCBkZWJ1Z2dpbmcNCm15X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpIHsNCiAgcHJpbnQocGFzdGUoIklucHV0OiIsIHgpKSAgIyBEZWJ1ZyBwcmludA0KICByZXN1bHQgPC0geCAqIDINCiAgcHJpbnQocGFzdGUoIlJlc3VsdDoiLCByZXN1bHQpKSAgIyBEZWJ1ZyBwcmludA0KICByZXR1cm4ocmVzdWx0KQ0KfQ0KDQojIFVzZSBicm93c2VyKCkgZm9yIGludGVyYWN0aXZlIGRlYnVnZ2luZw0KbXlfZnVuY3Rpb24gPC0gZnVuY3Rpb24oeCkgew0KICBicm93c2VyKCkgICMgRXhlY3V0aW9uIHN0b3BzIGhlcmUNCiAgcmVzdWx0IDwtIHggKiAyDQogIHJldHVybihyZXN1bHQpDQp9DQoNCiMgVXNlIGRlYnVnKCkgdG8gc3RlcCB0aHJvdWdoIGZ1bmN0aW9uDQpkZWJ1ZyhteV9mdW5jdGlvbikNCm15X2Z1bmN0aW9uKDUpDQp1bmRlYnVnKG15X2Z1bmN0aW9uKQ0KDQojIFVzZSB0cmFjZWJhY2soKSBhZnRlciBlcnJvcg0KIyAuLi4gZXJyb3Igb2NjdXJzIC4uLg0KdHJhY2ViYWNrKCkNCg0KIyBVc2UgdHJ5KCkgYW5kIHRyeUNhdGNoKCkgZm9yIGVycm9yIGhhbmRsaW5nDQpyZXN1bHQgPC0gdHJ5KGxvZygibm90IGEgbnVtYmVyIiksIHNpbGVudCA9IFRSVUUpDQppZiAoaW5oZXJpdHMocmVzdWx0LCAidHJ5LWVycm9yIikpIHsNCiAgcHJpbnQoIkFuIGVycm9yIG9jY3VycmVkISIpDQp9DQoNCiMgQmV0dGVyIGVycm9yIGhhbmRsaW5nIHdpdGggdHJ5Q2F0Y2goKQ0Kc2FmZV9sb2cgPC0gZnVuY3Rpb24oeCkgew0KICB0cnlDYXRjaCgNCiAgICB7DQogICAgICBsb2coeCkNCiAgICB9LA0KICAgIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgICAgbWVzc2FnZSgiRXJyb3I6ICIsIGUkbWVzc2FnZSkNCiAgICAgIHJldHVybihOQSkNCiAgICB9LA0KICAgIHdhcm5pbmcgPSBmdW5jdGlvbih3KSB7DQogICAgICBtZXNzYWdlKCJXYXJuaW5nOiAiLCB3JG1lc3NhZ2UpDQogICAgICByZXR1cm4obG9nKHgpKQ0KICAgIH0NCiAgKQ0KfQ0KDQpzYWZlX2xvZygiYWJjIikNCnNhZmVfbG9nKC01KQ0KYGBgDQoNCi0tLQ0KDQojIDIuIERhdGEgSGFuZGxpbmc6IEltcG9ydCwgRXhwb3J0LCBhbmQgTWFuaXB1bGF0aW9uDQoNCiMjIDIuMSBSZWFkaW5nIERhdGEgZnJvbSBWYXJpb3VzIFNvdXJjZXMNCg0KIyMjIENTViBhbmQgVGV4dCBGaWxlcw0KDQpgYGB7ciByZWFkX2NzdiwgZXZhbD1GQUxTRX0NCiMgQmFzZSBSDQpkZl9iYXNlIDwtIHJlYWQuY3N2KCJkYXRhL2ZpbGUuY3N2IikNCmRmX2Jhc2UgPC0gcmVhZC5jc3YoImRhdGEvZmlsZS5jc3YiLCANCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgc2VwID0gIiwiLA0KICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgcmVhZHIgKHRpZHl2ZXJzZSAtIEZBU1RFUiBhbmQgYmV0dGVyIGRlZmF1bHRzKQ0KbGlicmFyeShyZWFkcikNCmRmIDwtIHJlYWRfY3N2KCJkYXRhL2ZpbGUuY3N2IikgICMgQmV0dGVyIHRoYW4gcmVhZC5jc3YoKQ0KZGYgPC0gcmVhZF90c3YoImRhdGEvZmlsZS50eHQiKSAgIyBUYWItc2VwYXJhdGVkDQpkZiA8LSByZWFkX2RlbGltKCJkYXRhL2ZpbGUudHh0IiwgZGVsaW0gPSAifCIpICAjIEN1c3RvbSBkZWxpbWl0ZXINCg0KIyBSZWFkIGZyb20gVVJMDQp1cmwgPC0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9kYXRhc2V0cy9jb3ZpZC0xOS9tYXN0ZXIvZGF0YS9jb3VudHJpZXMtYWdncmVnYXRlZC5jc3YiDQpkZl91cmwgPC0gcmVhZF9jc3YodXJsKQ0KDQojIFJlYWQgd2l0aCBjb2x1bW4gc3BlY2lmaWNhdGlvbnMNCmRmIDwtIHJlYWRfY3N2KCJkYXRhL2ZpbGUuY3N2IiwNCiAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGNvbHMoDQogICAgICAgICAgICAgICAgIGlkID0gY29sX2ludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgbmFtZSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICAgICAgICAgICAgICAgZGF0ZSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWS0lbS0lZCIpLA0KICAgICAgICAgICAgICAgICB2YWx1ZSA9IGNvbF9kb3VibGUoKQ0KICAgICAgICAgICAgICAgKSkNCg0KIyBTa2lwIHJvd3MNCmRmIDwtIHJlYWRfY3N2KCJkYXRhL2ZpbGUuY3N2Iiwgc2tpcCA9IDIpDQoNCiMgUmVhZCBvbmx5IGZpcnN0IG4gcm93cw0KZGYgPC0gcmVhZF9jc3YoImRhdGEvZmlsZS5jc3YiLCBuX21heCA9IDEwMDApDQpgYGANCg0KIyMjIEV4Y2VsIEZpbGVzDQoNCmBgYHtyIHJlYWRfZXhjZWwsIGV2YWw9RkFMU0V9DQojIHJlYWR4bCBwYWNrYWdlIChwYXJ0IG9mIHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHhsKQ0KDQojIFJlYWQgZmlyc3Qgc2hlZXQNCmRmIDwtIHJlYWRfZXhjZWwoImRhdGEvZmlsZS54bHN4IikNCg0KIyBSZWFkIHNwZWNpZmljIHNoZWV0DQpkZiA8LSByZWFkX2V4Y2VsKCJkYXRhL2ZpbGUueGxzeCIsIHNoZWV0ID0gIlNoZWV0MiIpDQpkZiA8LSByZWFkX2V4Y2VsKCJkYXRhL2ZpbGUueGxzeCIsIHNoZWV0ID0gMikNCg0KIyBMaXN0IGFsbCBzaGVldHMNCmV4Y2VsX3NoZWV0cygiZGF0YS9maWxlLnhsc3giKQ0KDQojIFJlYWQgYWxsIHNoZWV0cyBhdCBvbmNlDQpmaWxlX3BhdGggPC0gImRhdGEvZmlsZS54bHN4Ig0KYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoZmlsZV9wYXRoKQ0KZGF0YV9saXN0IDwtIGxhcHBseShhbGxfc2hlZXRzLCBmdW5jdGlvbih4KSByZWFkX2V4Y2VsKGZpbGVfcGF0aCwgc2hlZXQgPSB4KSkNCm5hbWVzKGRhdGFfbGlzdCkgPC0gYWxsX3NoZWV0cw0KDQojIFJlYWQgc3BlY2lmaWMgcmFuZ2UNCmRmIDwtIHJlYWRfZXhjZWwoImRhdGEvZmlsZS54bHN4IiwgcmFuZ2UgPSAiQTE6RDEwIikNCg0KIyBXcml0aW5nIEV4Y2VsIGZpbGVzIChvcGVueGxzeCBwYWNrYWdlKQ0KbGlicmFyeShvcGVueGxzeCkNCndyaXRlLnhsc3goZGYsICJvdXRwdXQvZmlsZS54bHN4IikNCg0KIyBXcml0ZSBtdWx0aXBsZSBzaGVldHMNCndyaXRlLnhsc3gobGlzdChTaGVldDEgPSBkZjEsIFNoZWV0MiA9IGRmMiksICJvdXRwdXQvZmlsZS54bHN4IikNCmBgYA0KDQojIyMgRGF0YWJhc2UgQ29ubmVjdGlvbnMNCg0KYGBge3IgcmVhZF9kYXRhYmFzZSwgZXZhbD1GQUxTRX0NCiMgU1FMaXRlDQpsaWJyYXJ5KFJTUUxpdGUpDQpjb24gPC0gZGJDb25uZWN0KFNRTGl0ZSgpLCAiZGF0YS9kYXRhYmFzZS5zcWxpdGUiKQ0KZGYgPC0gZGJSZWFkVGFibGUoY29uLCAidGFibGVfbmFtZSIpDQoNCiMgU1FMIHF1ZXJ5DQpkZiA8LSBkYkdldFF1ZXJ5KGNvbiwgIlNFTEVDVCAqIEZST00gdGFibGVfbmFtZSBXSEVSRSB2YWx1ZSA+IDEwMCIpDQoNCiMgQ2xvc2UgY29ubmVjdGlvbg0KZGJEaXNjb25uZWN0KGNvbikNCg0KIyBQb3N0Z3JlU1FMDQpsaWJyYXJ5KFJQb3N0Z3JlU1FMKQ0KY29uIDwtIGRiQ29ubmVjdChQb3N0Z3JlU1FMKCksDQogICAgICAgICAgICAgICAgIGRibmFtZSA9ICJteWRiIiwNCiAgICAgICAgICAgICAgICAgaG9zdCA9ICJsb2NhbGhvc3QiLA0KICAgICAgICAgICAgICAgICBwb3J0ID0gNTQzMiwNCiAgICAgICAgICAgICAgICAgdXNlciA9ICJ1c2VybmFtZSIsDQogICAgICAgICAgICAgICAgIHBhc3N3b3JkID0gInBhc3N3b3JkIikNCg0KIyBNeVNRTA0KbGlicmFyeShSTXlTUUwpDQpjb24gPC0gZGJDb25uZWN0KE15U1FMKCksDQogICAgICAgICAgICAgICAgIGRibmFtZSA9ICJteWRiIiwNCiAgICAgICAgICAgICAgICAgaG9zdCA9ICJsb2NhbGhvc3QiLA0KICAgICAgICAgICAgICAgICB1c2VyID0gInVzZXJuYW1lIiwNCiAgICAgICAgICAgICAgICAgcGFzc3dvcmQgPSAicGFzc3dvcmQiKQ0KDQojIEdlbmVyaWMgREJJIGludGVyZmFjZQ0KbGlicmFyeShEQkkpDQpkZiA8LSBkYlJlYWRUYWJsZShjb24sICJ0YWJsZV9uYW1lIikNCmRiV3JpdGVUYWJsZShjb24sICJuZXdfdGFibGUiLCBkZikNCmBgYA0KDQojIyMgT3RoZXIgRm9ybWF0cw0KDQpgYGB7ciByZWFkX290aGVyLCBldmFsPUZBTFNFfQ0KIyBKU09ODQpsaWJyYXJ5KGpzb25saXRlKQ0KZGYgPC0gZnJvbUpTT04oImRhdGEvZmlsZS5qc29uIikNCmRhdGFfbGlzdCA8LSBmcm9tSlNPTigiZGF0YS9maWxlLmpzb24iLCBzaW1wbGlmeURhdGFGcmFtZSA9IEZBTFNFKQ0KDQojIFhNTA0KbGlicmFyeShYTUwpDQpkb2MgPC0geG1sUGFyc2UoImRhdGEvZmlsZS54bWwiKQ0KZGYgPC0geG1sVG9EYXRhRnJhbWUoZG9jKQ0KDQojIFNQU1MsIFNBUywgU3RhdGEgKGhhdmVuIHBhY2thZ2UpDQpsaWJyYXJ5KGhhdmVuKQ0KZGZfc3BzcyA8LSByZWFkX3NhdigiZGF0YS9maWxlLnNhdiIpICAgICMgU1BTUw0KZGZfc2FzIDwtIHJlYWRfc2FzKCJkYXRhL2ZpbGUuc2FzN2JkYXQiKSAgIyBTQVMNCmRmX3N0YXRhIDwtIHJlYWRfZHRhKCJkYXRhL2ZpbGUuZHRhIikgICAjIFN0YXRhDQoNCiMgUkRTIChSIG5hdGl2ZSBmb3JtYXQgLSBGQVNUISkNCnNhdmVSRFMoZGYsICJkYXRhL2ZpbGUucmRzIikNCmRmIDwtIHJlYWRSRFMoImRhdGEvZmlsZS5yZHMiKQ0KDQojIFJEYXRhIChtdWx0aXBsZSBvYmplY3RzKQ0Kc2F2ZShkZjEsIGRmMiwgZGYzLCBmaWxlID0gImRhdGEvd29ya3NwYWNlLlJEYXRhIikNCmxvYWQoImRhdGEvd29ya3NwYWNlLlJEYXRhIikNCg0KIyBmZWF0aGVyIChmYXN0IGZvcm1hdCBmb3IgUHl0aG9uL1IpDQpsaWJyYXJ5KGZlYXRoZXIpDQp3cml0ZV9mZWF0aGVyKGRmLCAiZGF0YS9maWxlLmZlYXRoZXIiKQ0KZGYgPC0gcmVhZF9mZWF0aGVyKCJkYXRhL2ZpbGUuZmVhdGhlciIpDQoNCiMgcGFycXVldCAoY29sdW1uYXIgZm9ybWF0KQ0KbGlicmFyeShhcnJvdykNCndyaXRlX3BhcnF1ZXQoZGYsICJkYXRhL2ZpbGUucGFycXVldCIpDQpkZiA8LSByZWFkX3BhcnF1ZXQoImRhdGEvZmlsZS5wYXJxdWV0IikNCmBgYA0KDQojIyAyLjIgRGF0YSBNYW5pcHVsYXRpb24gd2l0aCBkcGx5cg0KDQojIyMgRXNzZW50aWFsIGRwbHlyIFZlcmJzDQoNCmBgYHtyIGRwbHlyX2Jhc2ljc30NCmxpYnJhcnkoZHBseXIpDQoNCiMgU2FtcGxlIGRhdGENCmRhdGEoIm10Y2FycyIpDQpkZiA8LSBtdGNhcnMNCg0KIyAxLiBTRUxFQ1QgLSBDaG9vc2UgY29sdW1ucw0KZGYgJT4lIHNlbGVjdChtcGcsIGN5bCwgaHApDQpkZiAlPiUgc2VsZWN0KHN0YXJ0c193aXRoKCJjIikpDQpkZiAlPiUgc2VsZWN0KGVuZHNfd2l0aCgicCIpKQ0KZGYgJT4lIHNlbGVjdChjb250YWlucygiYSIpKQ0KZGYgJT4lIHNlbGVjdChtcGc6aHApICAjIFJhbmdlDQpkZiAlPiUgc2VsZWN0KC1jKG1wZywgY3lsKSkgICMgRXhjbHVkZSBjb2x1bW5zDQoNCiMgSGVscGVyIGZ1bmN0aW9ucw0KZGYgJT4lIHNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkNCmRmICU+JSBzZWxlY3QoZXZlcnl0aGluZygpKSAgIyBBbGwgY29sdW1ucw0KDQojIDIuIEZJTFRFUiAtIENob29zZSByb3dzDQpkZiAlPiUgZmlsdGVyKG1wZyA+IDIwKQ0KZGYgJT4lIGZpbHRlcihtcGcgPiAyMCAmIGN5bCA9PSA0KQ0KZGYgJT4lIGZpbHRlcihtcGcgPiAyMCB8IGN5bCA9PSA0KQ0KZGYgJT4lIGZpbHRlcihjeWwgJWluJSBjKDQsIDYpKQ0KZGYgJT4lIGZpbHRlcihiZXR3ZWVuKG1wZywgMTUsIDI1KSkNCg0KIyAzLiBNVVRBVEUgLSBDcmVhdGUvbW9kaWZ5IGNvbHVtbnMNCmRmICU+JQ0KICBtdXRhdGUoDQogICAgbXBnX3Blcl9jeWwgPSBtcGcgLyBjeWwsDQogICAgaHBfY2F0ZWdvcnkgPSBpZmVsc2UoaHAgPiAxNTAsICJIaWdoIiwgIkxvdyIpDQogICkNCg0KIyA0LiBBUlJBTkdFIC0gU29ydCByb3dzDQpkZiAlPiUgYXJyYW5nZShtcGcpICAjIEFzY2VuZGluZw0KZGYgJT4lIGFycmFuZ2UoZGVzYyhtcGcpKSAgIyBEZXNjZW5kaW5nDQpkZiAlPiUgYXJyYW5nZShjeWwsIGRlc2MobXBnKSkgICMgTXVsdGlwbGUgY29sdW1ucw0KDQojIDUuIFNVTU1BUklTRSAtIEFnZ3JlZ2F0ZSBkYXRhDQpkZiAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fbXBnID0gbWVhbihtcGcpLA0KICAgIG1lZGlhbl9tcGcgPSBtZWRpYW4obXBnKSwNCiAgICBzZF9tcGcgPSBzZChtcGcpLA0KICAgIG4gPSBuKCkNCiAgKQ0KDQojIDYuIEdST1VQX0JZIC0gR3JvdXAgb3BlcmF0aW9ucw0KZGYgJT4lDQogIGdyb3VwX2J5KGN5bCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX21wZyA9IG1lYW4obXBnKSwNCiAgICBtZWFuX2hwID0gbWVhbihocCksDQogICAgY291bnQgPSBuKCkNCiAgKQ0KDQojIDcuIERJU1RJTkNUIC0gVW5pcXVlIHJvd3MNCmRmICU+JSBkaXN0aW5jdChjeWwpDQpkZiAlPiUgZGlzdGluY3QoY3lsLCBnZWFyKQ0KDQojIDguIFNMSUNFIC0gU2VsZWN0IHJvd3MgYnkgcG9zaXRpb24NCmRmICU+JSBzbGljZSgxOjUpDQpkZiAlPiUgc2xpY2VfaGVhZChuID0gNSkNCmRmICU+JSBzbGljZV90YWlsKG4gPSA1KQ0KZGYgJT4lIHNsaWNlX21heChtcGcsIG4gPSA1KQ0KZGYgJT4lIHNsaWNlX3NhbXBsZShuID0gNSkNCmBgYA0KDQojIyMgQWR2YW5jZWQgZHBseXIgVGVjaG5pcXVlcw0KDQpgYGB7ciBkcGx5cl9hZHZhbmNlZH0NCiMgUmVuYW1lIGNvbHVtbnMNCmRmICU+JSByZW5hbWUobWlsZXNfcGVyX2dhbGxvbiA9IG1wZykNCg0KIyBSZWxvY2F0ZSBjb2x1bW5zDQpkZiAlPiUgcmVsb2NhdGUoaHAsIC5iZWZvcmUgPSBtcGcpDQpkZiAlPiUgcmVsb2NhdGUoY3lsLCAuYWZ0ZXIgPSBsYXN0X2NvbCgpKQ0KDQojIENvdW50IG9jY3VycmVuY2VzDQpkZiAlPiUgY291bnQoY3lsKQ0KZGYgJT4lIGNvdW50KGN5bCwgZ2VhcikNCg0KIyBBZGQgcm93IG51bWJlcnMNCmRmICU+JSBtdXRhdGUocm93X2lkID0gcm93X251bWJlcigpKQ0KDQojIEN1bXVsYXRpdmUgb3BlcmF0aW9ucw0KZGYgJT4lDQogIGFycmFuZ2UobXBnKSAlPiUNCiAgbXV0YXRlKA0KICAgIGN1bXN1bV9tcGcgPSBjdW1zdW0obXBnKSwNCiAgICByYW5rX21wZyA9IG1pbl9yYW5rKG1wZyksDQogICAgcGVyY2VudF9yYW5rX21wZyA9IHBlcmNlbnRfcmFuayhtcGcpDQogICkNCg0KIyBXaW5kb3cgZnVuY3Rpb25zDQpkZiAlPiUNCiAgZ3JvdXBfYnkoY3lsKSAlPiUNCiAgbXV0YXRlKA0KICAgIG1wZ19yYW5rX2luX2dyb3VwID0gcmFuayhtcGcpLA0KICAgIG1wZ192c19ncm91cF9tZWFuID0gbXBnIC0gbWVhbihtcGcpDQogICkNCg0KIyBNdWx0aXBsZSBzdW1tYXJpZXMNCmRmICU+JQ0KICBncm91cF9ieShjeWwpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgYWNyb3NzKGMobXBnLCBocCksIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKQ0KICApDQoNCiMgQ29uZGl0aW9uYWwgbXV0YXRpb25zDQpkZiAlPiUNCiAgbXV0YXRlKA0KICAgIGVmZmljaWVuY3kgPSBjYXNlX3doZW4oDQogICAgICBtcGcgPiAyNSB+ICJIaWdoIiwNCiAgICAgIG1wZyA+IDIwIH4gIk1lZGl1bSIsDQogICAgICBtcGcgPiAxNSB+ICJMb3ciLA0KICAgICAgVFJVRSB+ICJWZXJ5IExvdyINCiAgICApDQogICkNCmBgYA0KDQojIyMgSm9pbmluZyBEYXRhDQoNCmBgYHtyIGpvaW5zfQ0KIyBTYW1wbGUgZGF0YQ0KY3VzdG9tZXJzIDwtIGRhdGEuZnJhbWUoDQogIGlkID0gMTo1LA0KICBuYW1lID0gYygiQWxpY2UiLCAiQm9iIiwgIkNoYXJsaWUiLCAiRGF2aWQiLCAiRXZlIikNCikNCg0Kb3JkZXJzIDwtIGRhdGEuZnJhbWUoDQogIG9yZGVyX2lkID0gMTo2LA0KICBjdXN0b21lcl9pZCA9IGMoMSwgMSwgMiwgMywgMywgNiksDQogIGFtb3VudCA9IGMoMTAwLCAxNTAsIDIwMCwgNTAsIDc1LCAzMDApDQopDQoNCiMgSU5ORVIgSk9JTiAtIE9ubHkgbWF0Y2hpbmcgcm93cw0KaW5uZXJfam9pbihjdXN0b21lcnMsIG9yZGVycywgYnkgPSBjKCJpZCIgPSAiY3VzdG9tZXJfaWQiKSkNCg0KIyBMRUZUIEpPSU4gLSBBbGwgZnJvbSBsZWZ0LCBtYXRjaGluZyBmcm9tIHJpZ2h0DQpsZWZ0X2pvaW4oY3VzdG9tZXJzLCBvcmRlcnMsIGJ5ID0gYygiaWQiID0gImN1c3RvbWVyX2lkIikpDQoNCiMgUklHSFQgSk9JTiAtIEFsbCBmcm9tIHJpZ2h0LCBtYXRjaGluZyBmcm9tIGxlZnQNCnJpZ2h0X2pvaW4oY3VzdG9tZXJzLCBvcmRlcnMsIGJ5ID0gYygiaWQiID0gImN1c3RvbWVyX2lkIikpDQoNCiMgRlVMTCBKT0lOIC0gQWxsIHJvd3MgZnJvbSBib3RoDQpmdWxsX2pvaW4oY3VzdG9tZXJzLCBvcmRlcnMsIGJ5ID0gYygiaWQiID0gImN1c3RvbWVyX2lkIikpDQoNCiMgQU5USSBKT0lOIC0gUm93cyBpbiBsZWZ0IE5PVCBpbiByaWdodA0KYW50aV9qb2luKGN1c3RvbWVycywgb3JkZXJzLCBieSA9IGMoImlkIiA9ICJjdXN0b21lcl9pZCIpKQ0KDQojIFNFTUkgSk9JTiAtIFJvd3MgaW4gbGVmdCB0aGF0IGhhdmUgbWF0Y2ggaW4gcmlnaHQNCnNlbWlfam9pbihjdXN0b21lcnMsIG9yZGVycywgYnkgPSBjKCJpZCIgPSAiY3VzdG9tZXJfaWQiKSkNCmBgYA0KDQojIyAyLjMgRGF0YSBDbGVhbmluZyBUcmlja3MNCg0KIyMjIEhhbmRsaW5nIE1pc3NpbmcgVmFsdWVzDQoNCmBgYHtyIG1pc3NpbmdfdmFsdWVzfQ0KIyBDcmVhdGUgc2FtcGxlIGRhdGEgd2l0aCBtaXNzaW5nIHZhbHVlcw0KbGlicmFyeSh0aWR5cikNCmRmIDwtIGRhdGEuZnJhbWUoDQogIGlkID0gMToxMCwNCiAgdmFsdWUxID0gYygxLCAyLCBOQSwgNCwgNSwgTkEsIDcsIDgsIDksIDEwKSwNCiAgdmFsdWUyID0gYyhOQSwgMiwgMywgTkEsIDUsIDYsIDcsIE5BLCA5LCAxMCkNCikNCg0KIyBDaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMNCnN1bShpcy5uYShkZikpDQpjb2xTdW1zKGlzLm5hKGRmKSkNCmNvbXBsZXRlLmNhc2VzKGRmKQ0KDQojIFJlbW92ZSByb3dzIHdpdGggQU5ZIG1pc3NpbmcgdmFsdWVzDQpkZiAlPiUgbmEub21pdCgpDQpkZiAlPiUgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKQ0KDQojIFJlbW92ZSByb3dzIHdpdGggbWlzc2luZyBpbiBzcGVjaWZpYyBjb2x1bW4NCmRmICU+JSBmaWx0ZXIoIWlzLm5hKHZhbHVlMSkpDQoNCiMgUmVwbGFjZSBOQSB3aXRoIHZhbHVlDQpkZiAlPiUgDQogIG11dGF0ZSh2YWx1ZTEgPSByZXBsYWNlX25hKHZhbHVlMSwgMCkpDQoNCiMgUmVwbGFjZSBOQSB3aXRoIG1lYW4NCmRmICU+JQ0KICBtdXRhdGUodmFsdWUxID0gaWZlbHNlKGlzLm5hKHZhbHVlMSksIG1lYW4odmFsdWUxLCBuYS5ybSA9IFRSVUUpLCB2YWx1ZTEpKQ0KDQojIEZpbGwgTkEgd2l0aCBwcmV2aW91cy9uZXh0IHZhbHVlDQpkZiAlPiUNCiAgdGlkeXI6OmZpbGwodmFsdWUxLCAuZGlyZWN0aW9uID0gImRvd24iKQ0KDQojIENvdW50IG1pc3NpbmcgYnkgZ3JvdXANCmRmICU+JQ0KICBncm91cF9ieShpZCAlJSAyKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1pc3NpbmdfdmFsdWUxID0gc3VtKGlzLm5hKHZhbHVlMSkpLA0KICAgIG1pc3NpbmdfdmFsdWUyID0gc3VtKGlzLm5hKHZhbHVlMikpDQogICkNCmBgYA0KDQojIyMgSGFuZGxpbmcgRHVwbGljYXRlcw0KDQpgYGB7ciBkdXBsaWNhdGVzfQ0KIyBDcmVhdGUgZGF0YSB3aXRoIGR1cGxpY2F0ZXMNCmRmIDwtIGRhdGEuZnJhbWUoDQogIGlkID0gYygxLCAyLCAyLCAzLCA0LCA0LCA0KSwNCiAgbmFtZSA9IGMoIkEiLCAiQiIsICJCIiwgIkMiLCAiRCIsICJEIiwgIkQiKSwNCiAgdmFsdWUgPSBjKDEwLCAyMCwgMjAsIDMwLCA0MCwgNDAsIDQ1KQ0KKQ0KDQojIEZpbmQgZHVwbGljYXRlcw0KZGYgJT4lIGZpbHRlcihkdXBsaWNhdGVkKC4pIHwgZHVwbGljYXRlZCguLCBmcm9tTGFzdCA9IFRSVUUpKQ0KDQojIFJlbW92ZSBkdXBsaWNhdGVzIChrZWVwIGZpcnN0KQ0KZGYgJT4lIGRpc3RpbmN0KCkNCg0KIyBSZW1vdmUgYmFzZWQgb24gc3BlY2lmaWMgY29sdW1ucw0KZGYgJT4lIGRpc3RpbmN0KGlkLCBuYW1lLCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojIEtlZXAgcm93IHdpdGggbWF4IHZhbHVlIHBlciBncm91cA0KZGYgJT4lDQogIGdyb3VwX2J5KGlkLCBuYW1lKSAlPiUNCiAgc2xpY2VfbWF4KHZhbHVlLCBuID0gMSkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCiMjIyBTdHJpbmcgQ2xlYW5pbmcNCg0KYGBge3Igc3RyaW5nX2NsZWFuaW5nfQ0KbGlicmFyeShzdHJpbmdyKQ0KDQojIFNhbXBsZSBtZXNzeSBkYXRhDQp0ZXh0IDwtIGMoIiAgSGVsbG8gV29ybGQgICIsICJVUFBFUiBjYXNlIiwgInVuZGVyX3Njb3JlIiwgIjEyMy00NTYiKQ0KDQojIFRyaW0gd2hpdGVzcGFjZQ0Kc3RyX3RyaW0odGV4dCkNCg0KIyBDaGFuZ2UgY2FzZQ0Kc3RyX3RvX2xvd2VyKHRleHQpDQpzdHJfdG9fdXBwZXIodGV4dCkNCnN0cl90b190aXRsZSh0ZXh0KQ0KDQojIFJlcGxhY2UgcGF0dGVybnMNCnN0cl9yZXBsYWNlKHRleHQsICIgIiwgIl8iKQ0Kc3RyX3JlcGxhY2VfYWxsKHRleHQsICJbMC05XSIsICJYIikNCg0KIyBFeHRyYWN0IHBhdHRlcm5zDQpzdHJfZXh0cmFjdCh0ZXh0LCAiWzAtOV0rIikNCnN0cl9leHRyYWN0X2FsbCh0ZXh0LCAiWzAtOV0iKQ0KDQojIERldGVjdCBwYXR0ZXJucw0Kc3RyX2RldGVjdCh0ZXh0LCAiWzAtOV0iKQ0KDQojIFNwbGl0IHN0cmluZ3MNCnN0cl9zcGxpdCh0ZXh0LCAiICIpDQoNCiMgQ29uY2F0ZW5hdGUNCnN0cl9jKHRleHQsIGNvbGxhcHNlID0gIiB8ICIpDQpwYXN0ZSh0ZXh0LCBjb2xsYXBzZSA9ICIgfCAiKQ0KcGFzdGUwKCJJRF8iLCAxOjQpICAjIE5vIHNlcGFyYXRvcg0KYGBgDQoNCiMjIDIuNCBFeHBvcnRpbmcgRGF0YQ0KDQojIyMgV3JpdGluZyBGaWxlcw0KDQpgYGB7ciBleHBvcnRfZGF0YSwgZXZhbD1GQUxTRX0NCiMgQ1NWDQp3cml0ZS5jc3YoZGYsICJvdXRwdXQvZmlsZS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCndyaXRlX2NzdihkZiwgIm91dHB1dC9maWxlLmNzdiIpICAjIHJlYWRyIHZlcnNpb24gKGZhc3RlcikNCg0KIyBFeGNlbA0KbGlicmFyeShvcGVueGxzeCkNCndyaXRlLnhsc3goZGYsICJvdXRwdXQvZmlsZS54bHN4IikNCg0KIyBNdWx0aXBsZSBzaGVldHMNCndyaXRlLnhsc3gobGlzdChTaGVldDEgPSBkZjEsIFNoZWV0MiA9IGRmMiksICJvdXRwdXQvZmlsZS54bHN4IikNCg0KIyBSRFMgKHJlY29tbWVuZGVkIGZvciBSLXRvLVIpDQpzYXZlUkRTKGRmLCAib3V0cHV0L2ZpbGUucmRzIikNCg0KIyBSRGF0YSAobXVsdGlwbGUgb2JqZWN0cykNCnNhdmUoZGYxLCBkZjIsIGRmMywgZmlsZSA9ICJvdXRwdXQvd29ya3NwYWNlLlJEYXRhIikNCg0KIyBUYWItc2VwYXJhdGVkDQp3cml0ZS50YWJsZShkZiwgIm91dHB1dC9maWxlLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQojIEpTT04NCmxpYnJhcnkoanNvbmxpdGUpDQp3cml0ZV9qc29uKGRmLCAib3V0cHV0L2ZpbGUuanNvbiIpDQoNCiMgUGFycXVldCAoZWZmaWNpZW50IGZvciBsYXJnZSBkYXRhKQ0KbGlicmFyeShhcnJvdykNCndyaXRlX3BhcnF1ZXQoZGYsICJvdXRwdXQvZmlsZS5wYXJxdWV0IikNCmBgYA0KDQotLS0NCg0KIyAzLiBCaWcgRGF0YSBIYW5kbGluZyBUZWNobmlxdWVzDQoNCiMjIDMuMSBNZW1vcnkgTWFuYWdlbWVudA0KDQojIyMgVW5kZXJzdGFuZGluZyBNZW1vcnkgVXNhZ2UNCg0KYGBge3IgbWVtb3J5X21hbmFnZW1lbnR9DQojIENoZWNrIG9iamVjdCBzaXplDQpvYmplY3Quc2l6ZShtdGNhcnMpDQpwcmludChvYmplY3Quc2l6ZShtdGNhcnMpLCB1bml0cyA9ICJLYiIpDQoNCiMgTGlzdCBhbGwgb2JqZWN0cyBhbmQgdGhlaXIgc2l6ZXMNCnNvcnQoc2FwcGx5KGxzKCksIGZ1bmN0aW9uKHgpIG9iamVjdC5zaXplKGdldCh4KSkpLCBkZWNyZWFzaW5nID0gVFJVRSkNCg0KIyBSZW1vdmUgb2JqZWN0cw0Kcm0obGFyZ2Vfb2JqZWN0KQ0KDQojIENsZWFyIHdvcmtzcGFjZQ0KIyBybShsaXN0ID0gbHMoKSkgICMgVXNlIHdpdGggY2F1dGlvbiENCg0KIyBHYXJiYWdlIGNvbGxlY3Rpb24gKGZyZWUgdXAgbWVtb3J5KQ0KZ2MoKQ0KDQojIENoZWNrIG1lbW9yeSBsaW1pdA0KbWVtb3J5LmxpbWl0KCkgICMgV2luZG93cyBvbmx5DQpgYGANCg0KIyMjIE1lbW9yeS1FZmZpY2llbnQgRGF0YSBUeXBlcw0KDQpgYGB7ciBtZW1vcnlfZWZmaWNpZW50fQ0KIyBVc2UgYXBwcm9wcmlhdGUgZGF0YSB0eXBlcw0KIyBDaGFyYWN0ZXIgdXNlcyBtb3JlIG1lbW9yeSB0aGFuIGZhY3RvciAoZm9yIGNhdGVnb3JpY2FsIGRhdGEpDQoNCiMgQmFkOiBDaGFyYWN0ZXINCnZlY19jaGFyIDwtIHJlcChjKCJBIiwgIkIiLCAiQyIpLCAxMDAwKQ0Kb2JqZWN0LnNpemUodmVjX2NoYXIpDQoNCiMgR29vZDogRmFjdG9yDQp2ZWNfZmFjdG9yIDwtIGZhY3RvcihyZXAoYygiQSIsICJCIiwgIkMiKSwgMTAwMCkpDQpvYmplY3Quc2l6ZSh2ZWNfZmFjdG9yKQ0KDQojIEludGVnZXIgdnMgTnVtZXJpYw0KdmVjX251bWVyaWMgPC0gMToxMDAwMCAgIyBBY3R1YWxseSBpbnRlZ2VyDQpvYmplY3Quc2l6ZSh2ZWNfbnVtZXJpYykNCg0KdmVjX251bWVyaWMyIDwtIGFzLm51bWVyaWMoMToxMDAwMCkgICMgQWN0dWFsIG51bWVyaWMNCm9iamVjdC5zaXplKHZlY19udW1lcmljMikNCg0KIyBVc2UgYml0NjQgZm9yIGxhcmdlIGludGVnZXJzDQpsaWJyYXJ5KGJpdDY0KQ0KbGFyZ2VfaW50ZWdlcnMgPC0gYXMuaW50ZWdlcjY0KDE6MTAwMCkNCmBgYA0KDQojIyAzLjIgV29ya2luZyB3aXRoIExhcmdlIEZpbGVzDQoNCiMjIyBDaHVua2VkIFJlYWRpbmcNCg0KYGBge3IgY2h1bmtlZF9yZWFkaW5nLCBldmFsPUZBTFNFfQ0KIyBSZWFkIGluIGNodW5rcyB1c2luZyByZWFkcg0KbGlicmFyeShyZWFkcikNCg0KIyBEZWZpbmUgY2h1bmsgc2l6ZQ0KY2h1bmtfc2l6ZSA8LSAxMDAwMA0KDQojIFJlYWQgYW5kIHByb2Nlc3MgaW4gY2h1bmtzDQpwcm9jZXNzX2NodW5rIDwtIGZ1bmN0aW9uKGNodW5rLCBwb3MpIHsNCiAgIyBZb3VyIHByb2Nlc3NpbmcgaGVyZQ0KICBzdW1tYXJpc2VkIDwtIGNodW5rICU+JQ0KICAgIGdyb3VwX2J5KGNhdGVnb3J5KSAlPiUNCiAgICBzdW1tYXJpc2UobWVhbl92YWx1ZSA9IG1lYW4odmFsdWUpKQ0KICByZXR1cm4oc3VtbWFyaXNlZCkNCn0NCg0KIyBSZWFkIGZpbGUgaW4gY2h1bmtzDQpyZXN1bHRzIDwtIHJlYWRfY3N2X2NodW5rZWQoDQogICJkYXRhL2xhcmdlX2ZpbGUuY3N2IiwNCiAgY2FsbGJhY2sgPSBEYXRhRnJhbWVDYWxsYmFjayRuZXcocHJvY2Vzc19jaHVuayksDQogIGNodW5rX3NpemUgPSBjaHVua19zaXplDQopDQoNCiMgQWx0ZXJuYXRpdmU6IHJlYWRyIHdpdGggY2FsbGJhY2sNCmYgPC0gZnVuY3Rpb24oeCwgcG9zKSB7DQogIHN1YnNldCh4LCB2YWx1ZSA+IDEwMCkNCn0NCmxhcmdlX3N1YnNldCA8LSByZWFkX2Nzdl9jaHVua2VkKCJkYXRhL2xhcmdlX2ZpbGUuY3N2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0YUZyYW1lQ2FsbGJhY2skbmV3KGYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNodW5rX3NpemUgPSAxMDAwMCkNCmBgYA0KDQojIyMgVXNpbmcgZGF0YS50YWJsZSBmb3IgU3BlZWQNCg0KYGBge3IgZGF0YXRhYmxlfQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KDQojIENyZWF0ZSBzYW1wbGUgZGF0YQ0Kc2V0LnNlZWQoMTIzKQ0KZHQgPC0gZGF0YS50YWJsZSgNCiAgaWQgPSAxOjEwMDAwMDAsDQogIGdyb3VwID0gc2FtcGxlKExFVFRFUlNbMTo1XSwgMTAwMDAwMCwgcmVwbGFjZSA9IFRSVUUpLA0KICB2YWx1ZSA9IHJub3JtKDEwMDAwMDApDQopDQoNCiMgRmFzdCBzdWJzZXR0aW5nIChieSByZWZlcmVuY2UpDQpkdFt2YWx1ZSA+IDBdDQoNCiMgRmFzdCBhZ2dyZWdhdGlvbg0KZHRbLCAuKG1lYW5fdmFsdWUgPSBtZWFuKHZhbHVlKSksIGJ5ID0gZ3JvdXBdDQoNCiMgTXVsdGlwbGUgYWdncmVnYXRpb25zDQpkdFssIC4obWVhbl92YWwgPSBtZWFuKHZhbHVlKSwNCiAgICAgICBzZF92YWwgPSBzZCh2YWx1ZSksDQogICAgICAgY291bnQgPSAuTiksIA0KICAgYnkgPSBncm91cF0NCg0KIyBVcGRhdGUgYnkgcmVmZXJlbmNlIChubyBjb3B5ISkNCmR0WywgbmV3X2NvbHVtbiA6PSB2YWx1ZSAqIDJdDQoNCiMgQ29uZGl0aW9uYWwgdXBkYXRlDQpkdFt2YWx1ZSA+IDAsIGNhdGVnb3J5IDo9ICJwb3NpdGl2ZSJdDQpkdFt2YWx1ZSA8PSAwLCBjYXRlZ29yeSA6PSAibm9uLXBvc2l0aXZlIl0NCg0KIyBSZW1vdmUgY29sdW1uDQpkdFssIGNhdGVnb3J5IDo9IE5VTExdDQoNCiMgQ2hhaW5pbmcgb3BlcmF0aW9ucw0KZHRbdmFsdWUgPiAwXVtvcmRlcigtdmFsdWUpXVssIC4oaWQsIHZhbHVlKV0NCg0KIyBTZXQga2V5IGZvciBmYXN0IGpvaW5zDQpzZXRrZXkoZHQsIGdyb3VwKQ0KDQojIEZhc3QgbWVyZ2UNCmR0MiA8LSBkYXRhLnRhYmxlKA0KICBncm91cCA9IExFVFRFUlNbMTo1XSwNCiAgZ3JvdXBfbmFtZSA9IHBhc3RlKCJHcm91cCIsIExFVFRFUlNbMTo1XSkNCikNCnNldGtleShkdDIsIGdyb3VwKQ0KbWVyZ2VkIDwtIGR0W2R0Ml0NCmBgYA0KDQojIyMgVXNpbmcgQXJyb3cgZm9yIExhcmdlIEZpbGVzDQoNCmBgYHtyIGFycm93LCBldmFsPUZBTFNFfQ0KbGlicmFyeShhcnJvdykNCmxpYnJhcnkoZHBseXIpDQoNCiMgUmVhZCBwYXJxdWV0IGZpbGUgKGRvZXNuJ3QgbG9hZCBpbnRvIG1lbW9yeSkNCmRhdGFzZXQgPC0gb3Blbl9kYXRhc2V0KCJkYXRhL2xhcmdlX2ZpbGUucGFycXVldCIpDQoNCiMgUXVlcnkgd2l0aG91dCBsb2FkaW5nIGZ1bGwgZGF0YQ0KcmVzdWx0IDwtIGRhdGFzZXQgJT4lDQogIGZpbHRlcih2YWx1ZSA+IDEwMCkgJT4lDQogIGdyb3VwX2J5KGNhdGVnb3J5KSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fdmFsdWUgPSBtZWFuKHZhbHVlKSkgJT4lDQogIGNvbGxlY3QoKSAgIyBPbmx5IG5vdyBpcyBkYXRhIGxvYWRlZA0KDQojIFJlYWQgbXVsdGlwbGUgcGFycXVldCBmaWxlcyBhcyBvbmUgZGF0YXNldA0KZGF0YXNldCA8LSBvcGVuX2RhdGFzZXQoImRhdGEvcGFydGl0aW9uZWRfZGF0YS8iKQ0KDQojIFdyaXRlIHBhcnRpdGlvbmVkIHBhcnF1ZXQNCmRmICU+JQ0KICBncm91cF9ieSh5ZWFyLCBtb250aCkgJT4lDQogIHdyaXRlX2RhdGFzZXQoImRhdGEvcGFydGl0aW9uZWRfZGF0YS8iLCBmb3JtYXQgPSAicGFycXVldCIpDQpgYGANCg0KIyMgMy4zIFBhcmFsbGVsIFByb2Nlc3NpbmcNCg0KIyMjIFVzaW5nIHBhcmFsbGVsIFBhY2thZ2UNCg0KYGBge3IgcGFyYWxsZWxfcHJvY2Vzc2luZywgZXZhbD1GQUxTRX0NCmxpYnJhcnkocGFyYWxsZWwpDQoNCiMgRGV0ZWN0IG51bWJlciBvZiBjb3Jlcw0KbnVtX2NvcmVzIDwtIGRldGVjdENvcmVzKCkNCnByaW50KHBhc3RlKCJBdmFpbGFibGUgY29yZXM6IiwgbnVtX2NvcmVzKSkNCg0KIyBDcmVhdGUgY2x1c3Rlcg0KY2wgPC0gbWFrZUNsdXN0ZXIobnVtX2NvcmVzIC0gMSkgICMgTGVhdmUgb25lIGNvcmUgZnJlZQ0KDQojIFBhcmFsbGVsIGxhcHBseQ0KcmVzdWx0cyA8LSBwYXJMYXBwbHkoY2wsIDE6MTAwMCwgZnVuY3Rpb24oeCkgew0KICAjIFlvdXIgY29tcHV0YXRpb24gaGVyZQ0KICB4XjINCn0pDQoNCiMgU3RvcCBjbHVzdGVyIHdoZW4gZG9uZQ0Kc3RvcENsdXN0ZXIoY2wpDQoNCiMgVXNpbmcgbWNsYXBwbHkgKFVuaXgvTWFjIG9ubHkpDQpyZXN1bHRzIDwtIG1jbGFwcGx5KDE6MTAwMCwgZnVuY3Rpb24oeCkgeF4yLCBtYy5jb3JlcyA9IG51bV9jb3JlcyAtIDEpDQoNCiMgRXhhbXBsZTogUGFyYWxsZWwgZGF0YSBwcm9jZXNzaW5nDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQpyZWdpc3RlckRvUGFyYWxsZWwoY29yZXMgPSBudW1fY29yZXMgLSAxKQ0KDQpsaWJyYXJ5KGZvcmVhY2gpDQpyZXN1bHRzIDwtIGZvcmVhY2goaSA9IDE6MTAwMCwgLmNvbWJpbmUgPSByYmluZCkgJWRvcGFyJSB7DQogICMgWW91ciBwcm9jZXNzaW5nDQogIGRhdGEuZnJhbWUoaWQgPSBpLCByZXN1bHQgPSBpXjIpDQp9DQoNCnN0b3BJbXBsaWNpdENsdXN0ZXIoKQ0KYGBgDQoNCiMjIyBVc2luZyBmdXJyciBmb3IgUGFyYWxsZWwgcHVycnINCg0KYGBge3IgZnVycnIsIGV2YWw9RkFMU0V9DQpsaWJyYXJ5KGZ1cnJyKQ0KbGlicmFyeShwdXJycikNCg0KIyBTZXR1cCBwYXJhbGxlbCBwcm9jZXNzaW5nDQpwbGFuKG11bHRpc2Vzc2lvbiwgd29ya2VycyA9IDQpDQoNCiMgUmVndWxhciBwdXJycg0KcmVzdWx0X3NlcXVlbnRpYWwgPC0gbWFwKDE6MTAwLCB+IHNsb3dfZnVuY3Rpb24oLngpKQ0KDQojIFBhcmFsbGVsIHB1cnJyDQpyZXN1bHRfcGFyYWxsZWwgPC0gZnV0dXJlX21hcCgxOjEwMCwgfiBzbG93X2Z1bmN0aW9uKC54KSkNCg0KIyBXaXRoIHByb2dyZXNzIGJhcg0KcmVzdWx0X3BhcmFsbGVsIDwtIGZ1dHVyZV9tYXAoMToxMDAsIH4gc2xvd19mdW5jdGlvbigueCksIC5wcm9ncmVzcyA9IFRSVUUpDQpgYGANCg0KIyMgMy40IERhdGFiYXNlLWxpa2UgT3BlcmF0aW9ucw0KDQojIyMgVXNpbmcgZGJwbHlyDQoNCmBgYHtyIGRicGx5ciwgZXZhbD1GQUxTRX0NCmxpYnJhcnkoZGJwbHlyKQ0KbGlicmFyeShSU1FMaXRlKQ0KDQojIENvbm5lY3QgdG8gZGF0YWJhc2UNCmNvbiA8LSBkYkNvbm5lY3QoU1FMaXRlKCksICJkYXRhL2xhcmdlX2RhdGFiYXNlLnNxbGl0ZSIpDQoNCiMgQ3JlYXRlIGxhenkgdGFibGUgcmVmZXJlbmNlDQpkYl90YWJsZSA8LSB0YmwoY29uLCAibGFyZ2VfdGFibGUiKQ0KDQojIEFsbCBvcGVyYXRpb25zIGFyZSBsYXp5IChub3QgZXhlY3V0ZWQgdW50aWwgbmVlZGVkKQ0KcmVzdWx0IDwtIGRiX3RhYmxlICU+JQ0KICBmaWx0ZXIodmFsdWUgPiAxMDApICU+JQ0KICBncm91cF9ieShjYXRlZ29yeSkgJT4lDQogIHN1bW1hcmlzZShtZWFuX3ZhbHVlID0gbWVhbih2YWx1ZSkpDQoNCiMgVmlldyBTUUwgcXVlcnkgdGhhdCB3aWxsIGJlIGdlbmVyYXRlZA0Kc2hvd19xdWVyeShyZXN1bHQpDQoNCiMgRXhlY3V0ZSBhbmQgY29sbGVjdCByZXN1bHRzDQpmaW5hbF9yZXN1bHQgPC0gY29sbGVjdChyZXN1bHQpDQoNCiMgQ2xvc2UgY29ubmVjdGlvbg0KZGJEaXNjb25uZWN0KGNvbikNCmBgYA0KDQotLS0NCg0KIyA0LiBEYXRhIFZpc3VhbGl6YXRpb24gVHJpY2tzDQoNCiMjIDQuMSBnZ3Bsb3QyIEVzc2VudGlhbHMNCg0KIyMjIEJhc2ljIGdncGxvdDIgU3RydWN0dXJlDQoNCmBgYHtyIGdncGxvdF9iYXNpY3N9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgQmFzaWMgdGVtcGxhdGUNCiMgZ2dwbG90KGRhdGEsIGFlcyh4LCB5LCAuLi4pKSArIGdlb21fKigpICsgLi4uDQoNCiMgU2NhdHRlciBwbG90DQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKw0KICBnZW9tX3BvaW50KCkNCg0KIyBXaXRoIGNvbG9yDQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGZhY3RvcihjeWwpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzKSArDQogIGxhYnModGl0bGUgPSAiRnVlbCBFZmZpY2llbmN5IHZzIFdlaWdodCIsDQogICAgICAgeCA9ICJXZWlnaHQgKDEwMDAgbGJzKSIsDQogICAgICAgeSA9ICJNaWxlcyBQZXIgR2FsbG9uIiwNCiAgICAgICBjb2xvciA9ICJDeWxpbmRlcnMiKQ0KDQojIExpbmUgcGxvdA0KZ2dwbG90KGVjb25vbWljcywgYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgQmFyIHBsb3QNCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gZmFjdG9yKGN5bCkpKSArDQogIGdlb21fYmFyKGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBsYWJzKHRpdGxlID0gIkNvdW50IGJ5IEN5bGluZGVyIiwgeCA9ICJDeWxpbmRlcnMiLCB5ID0gIkNvdW50IikNCg0KIyBIaXN0b2dyYW0NCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAsIGZpbGwgPSAiZGFya2dyZWVuIiwgY29sb3IgPSAid2hpdGUiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQojIEJveCBwbG90DQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGZhY3RvcihjeWwpLCB5ID0gbXBnKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJsaWdodGJsdWUiKSArDQogIGdlb21faml0dGVyKHdpZHRoID0gMC4yLCBhbHBoYSA9IDAuMykNCmBgYA0KDQojIyMgQWR2YW5jZWQgZ2dwbG90MiBUcmlja3MNCg0KYGBge3IgZ2dwbG90X2FkdmFuY2VkfQ0KbGlicmFyeShkcGx5cikNCg0KIyBNdWx0aXBsZSBnZW9tcw0KZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZykpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBmYWN0b3IoY3lsKSksIHNpemUgPSAzKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgY29sb3IgPSAiYmxhY2siKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiTVBHIHZzIFdlaWdodCB3aXRoIExpbmVhciBUcmVuZCIpDQoNCiMgRmFjZXRpbmcNCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X3dyYXAofiBjeWwpICsNCiAgdGhlbWVfYncoKQ0KDQojIEN1c3RvbSB0aGVtZXMNCmN1c3RvbV90aGVtZSA8LSB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iDQogICkNCg0KZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgY29sb3IgPSBmYWN0b3IoY3lsKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKw0KICBjdXN0b21fdGhlbWUNCg0KIyBDb2xvciBwYWxldHRlcw0KbGlicmFyeSh2aXJpZGlzKQ0KZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgY29sb3IgPSBocCkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArDQogIHRoZW1lX2RhcmsoKQ0KDQojIEFubm90YXRpb25zDQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSA0LCB5ID0gMzAsIGxhYmVsID0gIkFubm90YXRpb24iLCBzaXplID0gNSkgKw0KICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSAzLCB4bWF4ID0gNCwgeW1pbiA9IDI1LCB5bWF4ID0gMzAsIA0KICAgICAgICAgICBhbHBoYSA9IDAuMiwgZmlsbCA9ICJyZWQiKQ0KDQojIENvb3JkaW5hdGVzDQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGZhY3RvcihjeWwpLCBmaWxsID0gZmFjdG9yKGdlYXIpKSkgKw0KICBnZW9tX2JhcigpICsNCiAgY29vcmRfcG9sYXIoKSAgIyBQaWUtbGlrZSBjaGFydA0KDQojIFNjYWxlcw0KZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2LCAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiKQ0KYGBgDQoNCiMjIyBRdWljayBQbG90dGluZyBUaXBzDQoNCmBgYHtyIHBsb3RfdGlwc30NCiMgRW5zdXJlIHRoZSBvdXRwdXQgZGlyZWN0b3J5IGV4aXN0cw0KaWYgKCFkaXIuZXhpc3RzKCJvdXRwdXQiKSkgew0KICBkaXIuY3JlYXRlKCJvdXRwdXQiLCByZWN1cnNpdmUgPSBUUlVFKQ0KfQ0KDQojIFNhdmUgdGhlIGxhc3QgcGxvdA0KZ2dzYXZlKCJvdXRwdXQvbXlfcGxvdC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KIyBTYXZlIGEgc3BlY2lmaWMgcGxvdA0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKyBnZW9tX3BvaW50KCkNCmdnc2F2ZSgib3V0cHV0L3NwZWNpZmljX3Bsb3QucG5nIiwgcGxvdCA9IHAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYpDQoNCiMgQ29tYmluZSBwbG90cyB1c2luZyBwYXRjaHdvcmsNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQpwMSA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKyBnZW9tX3BvaW50KCkNCnAyIDwtIGdncGxvdChtdGNhcnMsIGFlcyh4ID0gaHAsIHkgPSBtcGcpKSArIGdlb21fcG9pbnQoKQ0KcDMgPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSkpICsgZ2VvbV9iYXIoKQ0KDQojIFNpZGUgYnkgc2lkZQ0KcDEgKyBwMg0KDQojIFN0YWNrZWQNCnAxIC8gcDINCg0KIyBDb21wbGV4IGxheW91dA0KKHAxIHwgcDIpIC8gcDMNCg0KYGBgDQoNCiMjIDQuMiBJbnRlcmFjdGl2ZSBWaXN1YWxpemF0aW9ucw0KDQojIyMgcGxvdGx5DQoNCmBgYHtyIHBsb3RseSwgZXZhbD1GQUxTRX0NCmxpYnJhcnkocGxvdGx5KQ0KDQojIENvbnZlcnQgZ2dwbG90IHRvIHBsb3RseQ0KcCA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGZhY3RvcihjeWwpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzKQ0KDQpnZ3Bsb3RseShwKQ0KDQojIE5hdGl2ZSBwbG90bHkNCnBsb3RfbHkobXRjYXJzLCB4ID0gfnd0LCB5ID0gfm1wZywgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwNCiAgICAgICAgY29sb3IgPSB+ZmFjdG9yKGN5bCksIHNpemUgPSB+aHApDQoNCiMgM0Qgc2NhdHRlcg0KcGxvdF9seShtdGNhcnMsIHggPSB+d3QsIHkgPSB+aHAsIHogPSB+bXBnLCANCiAgICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gIm1hcmtlcnMiLA0KICAgICAgICBjb2xvciA9IH5mYWN0b3IoY3lsKSkNCmBgYA0KDQojIyMgT3RoZXIgVmlzdWFsaXphdGlvbiBQYWNrYWdlcw0KDQpgYGB7ciBvdGhlcl92aXosIGV2YWw9RkFMU0V9DQojIGhpZ2hjaGFydGVyDQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQ0KaGNoYXJ0KG10Y2FycywgInNjYXR0ZXIiLCBoY2Flcyh4ID0gd3QsIHkgPSBtcGcsIGdyb3VwID0gY3lsKSkNCg0KIyBlY2hhcnRzNHINCmxpYnJhcnkoZWNoYXJ0czRyKQ0KbXRjYXJzICU+JQ0KICBlX2NoYXJ0cyh3dCkgJT4lDQogIGVfc2NhdHRlcihtcGcpICU+JQ0KICBlX3RpdGxlKCJNUEcgdnMgV2VpZ2h0IikNCg0KIyBnZ3ZpcyAoaW50ZXJhY3RpdmUgZ2dwbG90LWxpa2UpDQpsaWJyYXJ5KGdndmlzKQ0KbXRjYXJzICU+JQ0KICBnZ3Zpcyh+d3QsIH5tcGcpICU+JQ0KICBsYXllcl9wb2ludHMoZmlsbCA9IH5mYWN0b3IoY3lsKSkNCmBgYA0KDQotLS0NCg0KIyA1LiBUaW1lIFNlcmllcyBEYXRhIEhhbmRsaW5nDQoNCiMjIDUuMSBUaW1lIFNlcmllcyBCYXNpY3MNCg0KDQojIyMgTHVicmlkYXRlIGZvciBEYXRlIE1hbmlwdWxhdGlvbg0KDQpgYGB7ciBsdWJyaWRhdGVfdHJpY2tzfQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCiMgUGFyc2luZyBkYXRlcw0KeW1kKCIyMDIzLTAxLTE1IikNCm1keSgiMDEvMTUvMjAyMyIpDQpkbXkoIjE1LTAxLTIwMjMiKQ0KDQojIERhdGUtdGltZQ0KeW1kX2htcygiMjAyMy0wMS0xNSAxNDozMDowMCIpDQoNCiMgRXh0cmFjdCBjb21wb25lbnRzDQpkYXRlIDwtIHltZCgiMjAyMy0wMS0xNSIpDQp5ZWFyKGRhdGUpDQptb250aChkYXRlKQ0KZGF5KGRhdGUpDQp3ZGF5KGRhdGUsIGxhYmVsID0gVFJVRSkNCnF1YXJ0ZXIoZGF0ZSkNCg0KIyBEYXRlIGFyaXRobWV0aWMNCmRhdGUgKyBkYXlzKDEwKQ0KZGF0ZSArIG1vbnRocygyKQ0KZGF0ZSArIHllYXJzKDEpDQoNCiMgSW50ZXJ2YWxzDQppbnRlcnZhbCh5bWQoIjIwMjMtMDEtMDEiKSwgeW1kKCIyMDIzLTEyLTMxIikpDQoNCiMgRHVyYXRpb25zDQpkdXJhdGlvbig1LCAiZGF5cyIpDQpkZGF5cyg1KQ0KZHdlZWtzKDIpDQoNCiMgUGVyaW9kcw0KcGVyaW9kKDUsICJkYXlzIikNCmRheXMoNSkNCndlZWtzKDIpDQoNCiMgVGltZSB6b25lcw0Kd2l0aF90eihub3coKSwgIkFtZXJpY2EvTmV3X1lvcmsiKQ0KZm9yY2VfdHoobm93KCksICJBbWVyaWNhL05ld19Zb3JrIikNCg0KIyBGbG9vci9jZWlsaW5nIGRhdGVzDQpmbG9vcl9kYXRlKGRhdGUsICJtb250aCIpDQpjZWlsaW5nX2RhdGUoZGF0ZSwgIm1vbnRoIikNCnJvdW5kX2RhdGUoZGF0ZSwgIm1vbnRoIikNCmBgYA0KDQoNCiMjIDUuMiBUaW1lIFNlcmllcyBWaXN1YWxpemF0aW9uDQoNCmBgYHtyIHRzX3Zpc3VhbGl6YXRpb259DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGR5Z3JhcGhzKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIENyZWF0ZSBleGFtcGxlIHRzIGRhdGENCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnNldC5zZWVkKDEyMykNCmRhdGVzIDwtIHNlcShhcy5EYXRlKCIyMDIwLTAxLTAxIiksIGFzLkRhdGUoIjIwMjAtMTItMzEiKSwgYnkgPSAiZGF5IikNCnZhbHVlcyA8LSBjdW1zdW0ocm5vcm0obGVuZ3RoKGRhdGVzKSkpDQoNCiMgQmFzZSBSIHRzIG9iamVjdCBmb3IgdGhlIGZpcnN0IHllYXINCnRzX2RhdGEgPC0gdHModmFsdWVzWzE6MzY1XSwgc3RhcnQgPSBjKDIwMjAsIDEpLCBmcmVxdWVuY3kgPSAzNjUpDQoNCg0KbGlicmFyeSh6b28pDQoNCnpvb190cyA8LSB6b28odHNfZGF0YSkNCnRzX2RmIDwtIGRhdGEuZnJhbWUoDQogIGRhdGUgPSBpbmRleCh6b29fdHMpLA0KICB2YWx1ZSA9IGNvcmVkYXRhKHpvb190cykNCikNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KHRzX2RmLCBhZXMoeCA9IGRhdGUsIHkgPSB2YWx1ZSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlRpbWUgU2VyaWVzIFBsb3QiKQ0KDQpgYGANCg0KIyMgNS4zIFRpbWUgU2VyaWVzIEFuYWx5c2lzDQoNCiMjIyBEZWNvbXBvc2l0aW9uDQoNCmBgYHtyIHRzX2RlY29tcG9zaXRpb259DQojIENyZWF0ZSBzZWFzb25hbCB0aW1lIHNlcmllcw0KbW9udGhseV90cyA8LSB0cyhybm9ybSgxMjApICsgMToxMjAvMTAgKyBzaW4oMipwaSooMToxMjApLzEyKSwgDQogICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDE1LCAxKSwgZnJlcXVlbmN5ID0gMTIpDQoNCiMgRGVjb21wb3NlDQpkZWNvbXBvc2VkIDwtIGRlY29tcG9zZShtb250aGx5X3RzKQ0KcGxvdChkZWNvbXBvc2VkKQ0KDQojIFNUTCBkZWNvbXBvc2l0aW9uIChtb3JlIHJvYnVzdCkNCnN0bF9yZXN1bHQgPC0gc3RsKG1vbnRobHlfdHMsIHMud2luZG93ID0gInBlcmlvZGljIikNCnBsb3Qoc3RsX3Jlc3VsdCkNCmBgYA0KDQojIyMgRm9yZWNhc3RpbmcgQmFzaWNzDQoNCmBgYHtyIGZvcmVjYXN0aW5nLCBldmFsPUZBTFNFfQ0KbGlicmFyeShmb3JlY2FzdCkNCg0KIyBBdXRvIEFSSU1BDQpmaXQgPC0gYXV0by5hcmltYShtb250aGx5X3RzKQ0KZm9yZWNhc3RlZCA8LSBmb3JlY2FzdChmaXQsIGggPSAxMikgICMgMTIgbW9udGhzIGFoZWFkDQpwbG90KGZvcmVjYXN0ZWQpDQoNCiMgRXhwb25lbnRpYWwgc21vb3RoaW5nDQpmaXRfZXRzIDwtIGV0cyhtb250aGx5X3RzKQ0KZm9yZWNhc3RlZF9ldHMgPC0gZm9yZWNhc3QoZml0X2V0cywgaCA9IDEyKQ0KcGxvdChmb3JlY2FzdGVkX2V0cykNCg0KIyBBY2N1cmFjeQ0KYWNjdXJhY3koZml0KQ0KYGBgDQoNCi0tLQ0KDQojIDYuIEdlb3NwYXRpYWwgRGF0YSBIYW5kbGluZyBUaXBzDQoNCiMjIDYuMSBRdWljayBHZW9zcGF0aWFsIFRyaWNrcw0KDQojIyMgRXNzZW50aWFsIHNmIE9wZXJhdGlvbnMNCg0KYGBge3IgZ2Vvc3BhdGlhbF90cmlja3MsIGV2YWw9RkFMU0V9DQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3BEYXRhKSAgIyBleGFtcGxlIHNwYXRpYWwgZGF0YXNldHMNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBVc2UgYnVpbHQtaW4gZXhhbXBsZSBkYXRhc2V0DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpzZl9kYXRhIDwtIHdvcmxkICAgICAgICAgICMgJ3dvcmxkJyBkYXRhc2V0IGZyb20gc3BEYXRhDQpzZl9kYXRhIDwtIHN0X2FzX3NmKHNmX2RhdGEpICAjIGVuc3VyZSBpdCdzIGFuIHNmIG9iamVjdA0KDQojIFF1aWNrIHBsb3QNCnBsb3Qoc3RfZ2VvbWV0cnkoc2ZfZGF0YSkpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQnVmZmVyIGV4YW1wbGUgKGluIG1ldGVycyBpZiBwcm9qZWN0ZWQpDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFRyYW5zZm9ybSB0byBhIHByb2plY3RlZCBDUlMgZm9yIG1ldGVycw0Kc2ZfcHJvaiA8LSBzdF90cmFuc2Zvcm0oc2ZfZGF0YSwgY3JzID0gMzg1NykNCmJ1ZmZlcmVkIDwtIHN0X2J1ZmZlcihzZl9wcm9qLCBkaXN0ID0gMTAwMDAwMCkgICMgMSwwMDAga20gYnVmZmVyDQoNCiMgUGxvdCBidWZmZXJlZCBnZW9tZXRyeQ0KcGxvdChzdF9nZW9tZXRyeShidWZmZXJlZCkpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgSW50ZXJzZWN0aW9uIGV4YW1wbGUNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTGV0J3MgaW50ZXJzZWN0IHR3byBjb3VudHJpZXMgYXMgZXhhbXBsZQ0Kb3RoZXJfc2YgPC0gc2ZfZGF0YSAlPiUgZmlsdGVyKG5hbWVfbG9uZyAlaW4lIGMoIkZyYW5jZSIsICJHZXJtYW55IikpDQpvdmVybGFwIDwtIHN0X2ludGVyc2VjdGlvbihvdGhlcl9zZiwgb3RoZXJfc2YpICAjIHNlbGYtaW50ZXJzZWN0aW9uIGp1c3QgYXMgZGVtbw0KcGxvdChzdF9nZW9tZXRyeShvdmVybGFwKSwgY29sID0gInJlZCIpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgRGlzdGFuY2UgbWF0cml4DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpkaXN0YW5jZXMgPC0gc3RfZGlzdGFuY2Uoc2ZfcHJvalsxOjUsIF0pICAjIG9ubHkgZmlyc3QgNSBmb3Igc2ltcGxpY2l0eQ0KcHJpbnQoZGlzdGFuY2VzKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIENlbnRyb2lkDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjZW50cm9pZHMgPC0gc3RfY2VudHJvaWQoc2ZfcHJvaikNCnBsb3Qoc3RfZ2VvbWV0cnkoY2VudHJvaWRzKSwgY29sID0gImJsdWUiLCBwY2ggPSAxNiwgYWRkID0gVFJVRSkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBcmVhIChpbiBwcm9qZWN0ZWQgQ1JTISkNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmFyZWFzIDwtIHN0X2FyZWEoc2ZfcHJvaikNCmhlYWQoYXJlYXMpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTmVhcmVzdCBmZWF0dXJlDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEV4YW1wbGU6IGZpbmQgbmVhcmVzdCBuZWlnaGJvciBmb3IgZmlyc3QgNSBjb3VudHJpZXMNCm5lYXJlc3QgPC0gc3RfbmVhcmVzdF9mZWF0dXJlKHNmX3Byb2pbMTo1LCBdLCBzZl9wcm9qWzY6MTAsIF0pDQpwcmludChuZWFyZXN0KQ0KDQpgYGANCg0KIyMjIFF1aWNrIE1hcHBpbmcNCg0KYGBge3IgcXVpY2tfbWFwcywgZXZhbD1GQUxTRX0NCmxpYnJhcnkobWFwdmlldykNCmxpYnJhcnkobGVhZmxldCkNCg0KIyBJbnN0YW50IGludGVyYWN0aXZlIG1hcA0KbWFwdmlldyhzZl9kYXRhKQ0KDQoNCg0KIyBMZWFmbGV0DQpsZWFmbGV0KHNmX2RhdGEpICU+JQ0KICBhZGRUaWxlcygpICU+JQ0KICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSAiYmx1ZSIsIHdlaWdodCA9IDEpDQpgYGANCg0KIyMgNi4yIFJhc3RlciBUaXBzDQoNCmBgYHtyIHJhc3Rlcl90aXBzLCBldmFsPUZBTFNFfQ0KIyBMb2FkIGxpYnJhcmllcw0KbGlicmFyeSh0ZXJyYSkNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBMb2FkIGV4YW1wbGUgcmFzdGVyDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBHZXQgdGhlIHBhdGggZm9yIHRoZSBpbmNsdWRlZCBleGFtcGxlIHJhc3RlciBmaWxlDQplbGV2X3BhdGggPC0gc3lzdGVtLmZpbGUoInJhc3Rlci9lbGV2LnRpZiIsIHBhY2thZ2UgPSAic3BEYXRhIikNCg0KIyBDaGVjayB0aGF0IGZpbGUgZXhpc3RzDQppZiAoZWxldl9wYXRoID09ICIiKSB7DQogIHN0b3AoIkV4YW1wbGUgcmFzdGVyIG5vdCBmb3VuZCDigJMgaW5zdGFsbCAnc3BEYXRhJyBhbmQgZW5zdXJlIGl0IGlzIHVwIHRvIGRhdGUuIikNCn0NCg0KIyBSZWFkIHJhc3RlciBhcyB0ZXJyYSBTcGF0UmFzdGVyDQpyIDwtIHJhc3QoZWxldl9wYXRoKQ0KDQojIFF1aWNrIHBsb3QNCnBsb3QociwgbWFpbiA9ICJFeGFtcGxlIEVsZXZhdGlvbiBSYXN0ZXIiKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBFeHRyYWN0IHJhc3RlciB2YWx1ZXMgYXQgcG9pbnRzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcG9pbnRzX3NmIDwtIHN0X2FzX3NmKA0KICBkYXRhLmZyYW1lKGxvbiA9IGMoLTAuMSwgMi4zKSwgbGF0ID0gYyg1MS41LCA0OC44KSksDQogIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwNCiAgY3JzID0gNDMyNg0KKQ0KDQojIENvbnZlcnQgc2YgdG8gdGVycmEgdmVjdG9yDQpwb2ludHNfdmVjdCA8LSB2ZWN0KHBvaW50c19zZikNCg0KIyBFeHRyYWN0IHJhc3RlciB2YWx1ZXMgYXQgdGhvc2UgcG9pbnRzDQpleHRyYWN0ZWQgPC0gdGVycmE6OmV4dHJhY3QociwgcG9pbnRzX3ZlY3QpDQpwcmludChleHRyYWN0ZWQpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFJhc3RlciBjYWxjdWxhdG9yDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcjIgPC0gciAqIDIgKyAxMDANCnBsb3QocjIsIG1haW4gPSAiUmFzdGVyIENhbGN1bGF0b3IiKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBZ2dyZWdhdGUgKGNvYXJzZXIgcmVzb2x1dGlvbikNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpyX2NvYXJzZSA8LSBhZ2dyZWdhdGUociwgZmFjdCA9IDUsIGZ1biA9IG1lYW4pDQpwbG90KHJfY29hcnNlLCBtYWluID0gIkFnZ3JlZ2F0ZWQgUmFzdGVyIikNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUmVzYW1wbGUgcmFzdGVyDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0Kcl9yZXNhbXBsZSA8LSByZXNhbXBsZShyLCByX2NvYXJzZSwgbWV0aG9kID0gImJpbGluZWFyIikNCnBsb3Qocl9yZXNhbXBsZSwgbWFpbiA9ICJSZXNhbXBsZWQgUmFzdGVyIikNCg0KDQpgYGANCg0KLS0tDQoNCiMgNy4gU2hpbnkgQXBwcyBCYXNpY3MNCg0KIyMgNy4xIFNoaW55IEFwcCBTdHJ1Y3R1cmUNCg0KIyMjIE1pbmltYWwgU2hpbnkgQXBwDQoNCmBgYHtyIHNoaW55X2Jhc2ljLCBldmFsPUZBTFNFfQ0KbGlicmFyeShzaGlueSkNCg0KIyBVSQ0KdWkgPC0gZmx1aWRQYWdlKA0KICB0aXRsZVBhbmVsKCJNeSBGaXJzdCBTaGlueSBBcHAiKSwNCiAgDQogIHNpZGViYXJMYXlvdXQoDQogICAgc2lkZWJhclBhbmVsKA0KICAgICAgc2xpZGVySW5wdXQoImJpbnMiLCAiTnVtYmVyIG9mIGJpbnM6IiwgDQogICAgICAgICAgICAgICAgICBtaW4gPSA1LCBtYXggPSA1MCwgdmFsdWUgPSAzMCkNCiAgICApLA0KICAgIA0KICAgIG1haW5QYW5lbCgNCiAgICAgIHBsb3RPdXRwdXQoImRpc3RQbG90IikNCiAgICApDQogICkNCikNCg0KIyBTZXJ2ZXINCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7DQogIG91dHB1dCRkaXN0UGxvdCA8LSByZW5kZXJQbG90KHsNCiAgICB4IDwtIGZhaXRoZnVsJHdhaXRpbmcNCiAgICBiaW5zIDwtIHNlcShtaW4oeCksIG1heCh4KSwgbGVuZ3RoLm91dCA9IGlucHV0JGJpbnMgKyAxKQ0KICAgIGhpc3QoeCwgYnJlYWtzID0gYmlucywgY29sID0gImRhcmtncmF5IiwgYm9yZGVyID0gIndoaXRlIiwNCiAgICAgICAgIHhsYWIgPSAiV2FpdGluZyB0aW1lIHRvIG5leHQgZXJ1cHRpb24gKGluIG1pbnMpIiwNCiAgICAgICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIHdhaXRpbmcgdGltZXMiKQ0KICB9KQ0KfQ0KDQojIFJ1biBhcHANCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikNCmBgYA0KDQojIyMgSW5wdXQvT3V0cHV0IFdpZGdldHMNCg0KYGBge3Igc2hpbnlfd2lkZ2V0cywgZXZhbD1GQUxTRX0NCiMgVUkgaW5wdXRzDQpzbGlkZXJJbnB1dCgic2xpZGVyIiwgIlNsaWRlcjoiLCBtaW4gPSAwLCBtYXggPSAxMDAsIHZhbHVlID0gNTApDQpudW1lcmljSW5wdXQoIm51bWJlciIsICJOdW1iZXI6IiwgdmFsdWUgPSAxMCkNCnRleHRJbnB1dCgidGV4dCIsICJUZXh0OiIsIHZhbHVlID0gIkVudGVyIHRleHQiKQ0Kc2VsZWN0SW5wdXQoInNlbGVjdCIsICJTZWxlY3Q6IiwgY2hvaWNlcyA9IGMoIkEiLCAiQiIsICJDIikpDQpjaGVja2JveElucHV0KCJjaGVja2JveCIsICJDaGVja2JveCIsIHZhbHVlID0gVFJVRSkNCmRhdGVJbnB1dCgiZGF0ZSIsICJEYXRlOiIpDQpmaWxlSW5wdXQoImZpbGUiLCAiQ2hvb3NlIGZpbGUiKQ0KDQojIE91dHB1dHMNCnBsb3RPdXRwdXQoInBsb3QiKQ0KdGFibGVPdXRwdXQoInRhYmxlIikNCnRleHRPdXRwdXQoInRleHQiKQ0KdmVyYmF0aW1UZXh0T3V0cHV0KCJjb2RlIikNCnVpT3V0cHV0KCJ1aSIpDQpgYGANCg0KIyMgNy4yIFJlYWN0aXZlIFByb2dyYW1taW5nDQoNCiMjIyBCYXNpYyBSZWFjdGl2aXR5DQoNCmBgYHtyIHJlYWN0aXZpdHksIGV2YWw9RkFMU0V9DQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgew0KICANCiAgIyBSZWFjdGl2ZSBleHByZXNzaW9uIChjb21wdXRlZCBvbmNlIHBlciBjaGFuZ2UpDQogIGRhdGFfZmlsdGVyZWQgPC0gcmVhY3RpdmUoew0KICAgIG10Y2FycyAlPiUgZmlsdGVyKGN5bCA9PSBpbnB1dCRjeWwpDQogIH0pDQogIA0KICAjIFVzZSByZWFjdGl2ZSBkYXRhDQogIG91dHB1dCRwbG90IDwtIHJlbmRlclBsb3Qoew0KICAgIGdncGxvdChkYXRhX2ZpbHRlcmVkKCksIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArIGdlb21fcG9pbnQoKQ0KICB9KQ0KICANCiAgb3V0cHV0JHRhYmxlIDwtIHJlbmRlclRhYmxlKHsNCiAgICBkYXRhX2ZpbHRlcmVkKCkNCiAgfSkNCiAgDQogICMgT2JzZXJ2ZSAoc2lkZSBlZmZlY3RzIG9ubHkpDQogIG9ic2VydmUoew0KICAgIHByaW50KHBhc3RlKCJDeWxpbmRlcnMgc2VsZWN0ZWQ6IiwgaW5wdXQkY3lsKSkNCiAgfSkNCiAgDQogICMgb2JzZXJ2ZUV2ZW50IChyZWFjdCB0byBzcGVjaWZpYyBpbnB1dCkNCiAgb2JzZXJ2ZUV2ZW50KGlucHV0JGJ1dHRvbiwgew0KICAgIHNob3dNb2RhbChtb2RhbERpYWxvZygiQnV0dG9uIGNsaWNrZWQhIikpDQogIH0pDQp9DQpgYGANCg0KIyMgNy4zIFNoaW55IERhc2hib2FyZA0KDQpgYGB7ciBzaGlueWRhc2hib2FyZCwgZXZhbD1GQUxTRX0NCmxpYnJhcnkoc2hpbnlkYXNoYm9hcmQpDQoNCnVpIDwtIGRhc2hib2FyZFBhZ2UoDQogIGRhc2hib2FyZEhlYWRlcih0aXRsZSA9ICJNeSBEYXNoYm9hcmQiKSwNCiAgDQogIGRhc2hib2FyZFNpZGViYXIoDQogICAgc2lkZWJhck1lbnUoDQogICAgICBtZW51SXRlbSgiRGFzaGJvYXJkIiwgdGFiTmFtZSA9ICJkYXNoYm9hcmQiLCBpY29uID0gaWNvbigiZGFzaGJvYXJkIikpLA0KICAgICAgbWVudUl0ZW0oIkRhdGEiLCB0YWJOYW1lID0gImRhdGEiLCBpY29uID0gaWNvbigidGFibGUiKSkNCiAgICApDQogICksDQogIA0KICBkYXNoYm9hcmRCb2R5KA0KICAgIHRhYkl0ZW1zKA0KICAgICAgdGFiSXRlbSh0YWJOYW1lID0gImRhc2hib2FyZCIsDQogICAgICAgICAgICAgIGZsdWlkUm93KA0KICAgICAgICAgICAgICAgIHZhbHVlQm94T3V0cHV0KCJ2YWx1ZTEiKSwNCiAgICAgICAgICAgICAgICB2YWx1ZUJveE91dHB1dCgidmFsdWUyIikNCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgZmx1aWRSb3coDQogICAgICAgICAgICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QxIiksIHdpZHRoID0gNiksDQogICAgICAgICAgICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QyIiksIHdpZHRoID0gNikNCiAgICAgICAgICAgICAgKQ0KICAgICAgKSwNCiAgICAgIA0KICAgICAgdGFiSXRlbSh0YWJOYW1lID0gImRhdGEiLA0KICAgICAgICAgICAgICBmbHVpZFJvdygNCiAgICAgICAgICAgICAgICBib3godGFibGVPdXRwdXQoInRhYmxlIiksIHdpZHRoID0gMTIpDQogICAgICAgICAgICAgICkNCiAgICAgICkNCiAgICApDQogICkNCikNCg0Kc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQpIHsNCiAgb3V0cHV0JHZhbHVlMSA8LSByZW5kZXJWYWx1ZUJveCh7DQogICAgdmFsdWVCb3gobnJvdyhtdGNhcnMpLCAiVG90YWwgQ2FycyIsIGljb24gPSBpY29uKCJjYXIiKSkNCiAgfSkNCiAgDQogIG91dHB1dCRwbG90MSA8LSByZW5kZXJQbG90KHsNCiAgICBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKyBnZW9tX3BvaW50KCkNCiAgfSkNCiAgDQogIG91dHB1dCR0YWJsZSA8LSByZW5kZXJUYWJsZSh7DQogICAgaGVhZChtdGNhcnMpDQogIH0pDQp9DQoNCnNoaW55QXBwKHVpLCBzZXJ2ZXIpDQpgYGANCg0KIyMgNy40IFNoaW55IFRpcHMgYW5kIFRyaWNrcw0KDQpgYGB7ciBzaGlueV90aXBzLCBldmFsPUZBTFNFfQ0KIyAxLiBVc2UgaXNvbGF0ZSgpIHRvIHByZXZlbnQgcmVhY3Rpdml0eQ0Kb3V0cHV0JHBsb3QgPC0gcmVuZGVyUGxvdCh7DQogICMgT25seSByZWFjdHMgdG8gaW5wdXQkdXBkYXRlLCBub3QgaW5wdXQkYmlucw0KICBpbnB1dCR1cGRhdGUNCiAgaXNvbGF0ZSh7DQogICAgaGlzdChybm9ybSgxMDApLCBicmVha3MgPSBpbnB1dCRiaW5zKQ0KICB9KQ0KfSkNCg0KIyAyLiBVc2UgZXZlbnRSZWFjdGl2ZSgpIGZvciBiZXR0ZXIgY29udHJvbA0KZGF0YV9wcm9jZXNzZWQgPC0gZXZlbnRSZWFjdGl2ZShpbnB1dCRnb19idXR0b24sIHsNCiAgIyBPbmx5IHJ1bnMgd2hlbiBidXR0b24gaXMgY2xpY2tlZA0KICBwcm9jZXNzX2RhdGEoaW5wdXQkZGF0YSkNCn0pDQoNCiMgMy4gVXNlIHJlcSgpIHRvIHByZXZlbnQgZXJyb3JzDQpvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsNCiAgcmVxKGlucHV0JGZpbGUpICAjIERvbid0IHJ1biBpZiBmaWxlIG5vdCB1cGxvYWRlZA0KICBkYXRhIDwtIHJlYWQuY3N2KGlucHV0JGZpbGUkZGF0YXBhdGgpDQogIHBsb3QoZGF0YSkNCn0pDQoNCiMgNC4gVXNlIHZhbGlkYXRlKCkgZm9yIGN1c3RvbSBlcnJvciBtZXNzYWdlcw0Kb3V0cHV0JHBsb3QgPC0gcmVuZGVyUGxvdCh7DQogIHZhbGlkYXRlKA0KICAgIG5lZWQoaW5wdXQkZGF0YSAhPSAiIiwgIlBsZWFzZSB1cGxvYWQgZGF0YSIpLA0KICAgIG5lZWQobnJvdyhpbnB1dCRkYXRhKSA+IDEwLCAiTmVlZCBhdCBsZWFzdCAxMCByb3dzIikNCiAgKQ0KICBwbG90KGlucHV0JGRhdGEpDQp9KQ0KDQojIDUuIFVzZSB1cGRhdGVJbnB1dCgpIHRvIGNoYW5nZSBpbnB1dHMgZnJvbSBzZXJ2ZXINCm9ic2VydmVFdmVudChpbnB1dCRyZXNldCwgew0KICB1cGRhdGVTbGlkZXJJbnB1dChzZXNzaW9uLCAiYmlucyIsIHZhbHVlID0gMzApDQogIHVwZGF0ZVRleHRJbnB1dChzZXNzaW9uLCAidGV4dCIsIHZhbHVlID0gIiIpDQp9KQ0KDQojIDYuIFVzZSBkb3dubG9hZEhhbmRsZXIgZm9yIGZpbGUgZG93bmxvYWRzDQpvdXRwdXQkZG93bmxvYWQgPC0gZG93bmxvYWRIYW5kbGVyKA0KICBmaWxlbmFtZSA9IGZ1bmN0aW9uKCkgew0KICAgIHBhc3RlKCJkYXRhLSIsIFN5cy5EYXRlKCksICIuY3N2Iiwgc2VwID0gIiIpDQogIH0sDQogIGNvbnRlbnQgPSBmdW5jdGlvbihmaWxlKSB7DQogICAgd3JpdGUuY3N2KGRhdGEoKSwgZmlsZSwgcm93Lm5hbWVzID0gRkFMU0UpDQogIH0NCikNCg0KIyA3LiBVc2Ugc2hpbnlqcyBmb3IgSmF2YVNjcmlwdCBpbnRlcmFjdGlvbnMNCmxpYnJhcnkoc2hpbnlqcykNCnVzZVNoaW55anMoKSAgIyBJbiBVSQ0Kb25jbGljaygiYnV0dG9uIiwgYWxlcnQoIkNsaWNrZWQhIikpDQpoaWRlKCJlbGVtZW50IikNCnNob3coImVsZW1lbnQiKQ0KYGBgDQoNCi0tLQ0KDQojIDguIFBlcmZvcm1hbmNlIE9wdGltaXphdGlvbiBUaXBzDQoNCiMjIDguMSBDb2RlIFByb2ZpbGluZw0KDQpgYGB7ciBwcm9maWxpbmcsIGV2YWw9RkFMU0V9DQojIFByb2ZpbGUgY29kZSBleGVjdXRpb24gdGltZQ0KbGlicmFyeShwcm9mdmlzKQ0KDQpwcm9mdmlzKHsNCiAgIyBZb3VyIGNvZGUgaGVyZQ0KICB4IDwtIG51bWVyaWMoMTAwMCkNCiAgZm9yKGkgaW4gMToxMDAwKSB7DQogICAgeFtpXSA8LSBpXjINCiAgfQ0KfSkNCg0KIyBCZW5jaG1hcmsgYWx0ZXJuYXRpdmVzDQpsaWJyYXJ5KG1pY3JvYmVuY2htYXJrKQ0KDQptaWNyb2JlbmNobWFyaygNCiAgbG9vcCA9IHsNCiAgICB4IDwtIG51bWVyaWMoMTAwMCkNCiAgICBmb3IoaSBpbiAxOjEwMDApIHhbaV0gPC0gaV4yDQogIH0sDQogIHZlY3Rvcml6ZWQgPSB7DQogICAgeCA8LSAoMToxMDAwKV4yDQogIH0sDQogIHRpbWVzID0gMTAwDQopDQpgYGANCg0KIyMgOC4yIFZlY3Rvcml6YXRpb24gVHJpY2tzDQoNCmBgYHtyIHZlY3Rvcml6YXRpb259DQojIEFsd2F5cyBwcmVmZXIgdmVjdG9yaXplZCBvcGVyYXRpb25zDQoNCiMgQkFEIC0gTG9vcA0KcmVzdWx0IDwtIG51bWVyaWMoMTAwMCkNCmZvcihpIGluIDE6MTAwMCkgew0KICByZXN1bHRbaV0gPC0gc3FydChpKQ0KfQ0KDQojIEdPT0QgLSBWZWN0b3JpemVkDQpyZXN1bHQgPC0gc3FydCgxOjEwMDApDQoNCiMgVXNlIGFwcGx5IGZhbWlseQ0KbWF0IDwtIG1hdHJpeCgxOjEyLCAzLCA0KQ0KYXBwbHkobWF0LCAyLCBzdW0pICAjIENvbHVtbiBzdW1zDQpjb2xTdW1zKG1hdCkgICMgRXZlbiBmYXN0ZXIhDQoNCiMgVXNlIGlmZWxzZSBpbnN0ZWFkIG9mIGlmLWVsc2UgaW4gbG9vcHMNCnggPC0gMToxMA0KaWZlbHNlKHggPiA1LCAiSGlnaCIsICJMb3ciKQ0KYGBgDQoNCiMjIDguMyBDb21waWxhdGlvbg0KDQpgYGB7ciBjb21waWxhdGlvbiwgZXZhbD1GQUxTRX0NCiMgVXNlIGNvbXBpbGVyIHBhY2thZ2UNCmxpYnJhcnkoY29tcGlsZXIpDQoNCiMgQ29tcGlsZSBmdW5jdGlvbg0KbXlfZnVuYyA8LSBmdW5jdGlvbihuKSB7DQogIHJlc3VsdCA8LSAwDQogIGZvcihpIGluIDE6bikgcmVzdWx0IDwtIHJlc3VsdCArIGkNCiAgcmVzdWx0DQp9DQoNCm15X2Z1bmNfY29tcGlsZWQgPC0gY21wZnVuKG15X2Z1bmMpDQoNCiMgVGVzdCBzcGVlZA0KbWljcm9iZW5jaG1hcmsoDQogIG9yaWdpbmFsID0gbXlfZnVuYygxMDAwMCksDQogIGNvbXBpbGVkID0gbXlfZnVuY19jb21waWxlZCgxMDAwMCksDQogIHRpbWVzID0gMTAwDQopDQpgYGANCg0KLS0tDQoNCiMgOS4gQmVzdCBQcmFjdGljZXMgU3VtbWFyeQ0KDQojIyA5LjEgUHJvamVjdCBPcmdhbml6YXRpb24NCg0KYGBgDQpteV9wcm9qZWN0Lw0K4pSCDQrilJzilIDilIAgUkVBRE1FLm1kICAgICAgICAgICAgICAgICAjIFByb2plY3Qgb3ZlcnZpZXcNCuKUnOKUgOKUgCBteV9wcm9qZWN0LlJwcm9qICAgICAgICAgIyBSU3R1ZGlvIHByb2plY3QgZmlsZQ0K4pSCDQrilJzilIDilIAgZGF0YS8NCuKUgiAgIOKUnOKUgOKUgCByYXcvICAgICAgICAgICAgICAgICAjIE9yaWdpbmFsLCBpbW11dGFibGUgZGF0YQ0K4pSCICAg4pSU4pSA4pSAIHByb2Nlc3NlZC8gICAgICAgICAgICMgQ2xlYW5lZCwgcHJvY2Vzc2VkIGRhdGENCuKUgg0K4pSc4pSA4pSAIHNjcmlwdHMvDQrilIIgICDilJzilIDilIAgMDFfZGF0YV9pbXBvcnQuUg0K4pSCICAg4pSc4pSA4pSAIDAyX2RhdGFfY2xlYW5pbmcuUg0K4pSCICAg4pSc4pSA4pSAIDAzX2FuYWx5c2lzLlINCuKUgiAgIOKUlOKUgOKUgCAwNF92aXN1YWxpemF0aW9uLlINCuKUgg0K4pSc4pSA4pSAIG91dHB1dC8NCuKUgiAgIOKUnOKUgOKUgCBmaWd1cmVzLw0K4pSCICAg4pSU4pSA4pSAIHRhYmxlcy8NCuKUgg0K4pSc4pSA4pSAIHJlcG9ydHMvDQrilIIgICDilJTilIDilIAgYW5hbHlzaXNfcmVwb3J0LlJtZA0K4pSCDQrilJTilIDilIAgZnVuY3Rpb25zLw0KICAgIOKUlOKUgOKUgCBoZWxwZXJfZnVuY3Rpb25zLlINCmBgYA0KDQojIyA5LjIgQ29kZSBTdHlsZSBHdWlkZQ0KDQpgYGB7ciBzdHlsZV9ndWlkZSwgZXZhbD1GQUxTRX0NCiMgVXNlIHN0eWxlciBwYWNrYWdlIHRvIGF1dG8tZm9ybWF0IGNvZGUNCmxpYnJhcnkoc3R5bGVyKQ0Kc3R5bGVfZmlsZSgic2NyaXB0LlIiKQ0Kc3R5bGVfZGlyKCJzY3JpcHRzLyIpDQoNCiMgVXNlIGxpbnRyIHRvIGNoZWNrIGNvZGUgcXVhbGl0eQ0KbGlicmFyeShsaW50cikNCmxpbnQoInNjcmlwdC5SIikNCg0KIyBOYW1pbmcgY29udmVudGlvbnM6DQojIC0gc25ha2VfY2FzZSBmb3IgdmFyaWFibGVzIGFuZCBmdW5jdGlvbnMNCiMgLSBVUFBFUkNBU0UgZm9yIGNvbnN0YW50cw0KIyAtIE1lYW5pbmdmdWwgbmFtZXMNCg0KIyBHb29kIHNwYWNpbmcNCnggPC0gNSArIDMgICMgR09PRA0KeDwtNSszICAgICAgIyBCQUQNCg0KIyBDb21tZW50IHlvdXIgY29kZQ0KIyBDYWxjdWxhdGUgYXZlcmFnZSBhZ2Ugb2YgY3VzdG9tZXJzDQptZWFuX2FnZSA8LSBtZWFuKGN1c3RvbWVyX2RhdGEkYWdlKQ0KDQojIFVzZSBmdW5jdGlvbnMgZm9yIHJlcGVhdGVkIGNvZGUNCmNhbGN1bGF0ZV9tZXRyaWNzIDwtIGZ1bmN0aW9uKGRhdGEpIHsNCiAgIyBZb3VyIGNvZGUNCn0NCmBgYA0KDQojIyA5LjMgVmVyc2lvbiBDb250cm9sDQoNCmBgYHtiYXNoIGdpdCwgZXZhbD1GQUxTRX0NCiMgSW5pdGlhbGl6ZSBnaXQgcmVwb3NpdG9yeQ0KZ2l0IGluaXQNCg0KIyBDcmVhdGUgLmdpdGlnbm9yZQ0KIyBBZGQ6ICouUkRhdGEsICouUmhpc3RvcnksIC5ScHJvai51c2VyLywgZGF0YS8NCg0KIyBDb21taXQgY2hhbmdlcw0KZ2l0IGFkZCAuDQpnaXQgY29tbWl0IC1tICJJbml0aWFsIGNvbW1pdCINCg0KIyBDb25uZWN0IHRvIEdpdEh1Yg0KZ2l0IHJlbW90ZSBhZGQgb3JpZ2luIGh0dHBzOi8vZ2l0aHViLmNvbS91c2VybmFtZS9yZXBvLmdpdA0KZ2l0IHB1c2ggLXUgb3JpZ2luIG1haW4NCmBgYA0KDQotLS0NCg0KIyAxMC4gRXNzZW50aWFsIFIgUGFja2FnZXMgQ2hlYXQgU2hlZXQNCg0KIyMgMTAuMSBEYXRhIE1hbmlwdWxhdGlvbg0KDQp8IFBhY2thZ2UgfCBQdXJwb3NlIHwgS2V5IEZ1bmN0aW9ucyB8DQp8LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS18DQp8IGBkcGx5cmAgfCBEYXRhIG1hbmlwdWxhdGlvbiB8IGBzZWxlY3QoKWAsIGBmaWx0ZXIoKWAsIGBtdXRhdGUoKWAsIGBzdW1tYXJpc2UoKWAsIGBncm91cF9ieSgpYCB8DQp8IGB0aWR5cmAgfCBEYXRhIHJlc2hhcGluZyB8IGBwaXZvdF9sb25nZXIoKWAsIGBwaXZvdF93aWRlcigpYCwgYHNlcGFyYXRlKClgLCBgdW5pdGUoKWAgfA0KfCBgZGF0YS50YWJsZWAgfCBGYXN0IGRhdGEgbWFuaXB1bGF0aW9uIHwgYFtpLCBqLCBieV1gLCBgOj1gLCBgc2V0a2V5KClgIHwNCnwgYHN0cmluZ3JgIHwgU3RyaW5nIG1hbmlwdWxhdGlvbiB8IGBzdHJfZGV0ZWN0KClgLCBgc3RyX3JlcGxhY2UoKWAsIGBzdHJfZXh0cmFjdCgpYCB8DQp8IGBsdWJyaWRhdGVgIHwgRGF0ZS90aW1lIGhhbmRsaW5nIHwgYHltZCgpYCwgYGZsb29yX2RhdGUoKWAsIGBpbnRlcnZhbCgpYCB8DQoNCiMjIDEwLjIgVmlzdWFsaXphdGlvbg0KDQp8IFBhY2thZ2UgfCBQdXJwb3NlIHwgS2V5IEZ1bmN0aW9ucyB8DQp8LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS18DQp8IGBnZ3Bsb3QyYCB8IFN0YXRpYyBwbG90cyB8IGBnZ3Bsb3QoKWAsIGBnZW9tXyooKWAsIGB0aGVtZV8qKClgIHwNCnwgYHBsb3RseWAgfCBJbnRlcmFjdGl2ZSBwbG90cyB8IGBwbG90X2x5KClgLCBgZ2dwbG90bHkoKWAgfA0KfCBgbGVhZmxldGAgfCBJbnRlcmFjdGl2ZSBtYXBzIHwgYGxlYWZsZXQoKWAsIGBhZGRUaWxlcygpYCwgYGFkZE1hcmtlcnMoKWAgfA0KfCBgZ2dhbmltYXRlYCB8IEFuaW1hdGVkIHBsb3RzIHwgYHRyYW5zaXRpb25fKigpYCwgYGFuaW1hdGUoKWAgfA0KDQojIyAxMC4zIE1vZGVsaW5nICYgU3RhdHMNCg0KfCBQYWNrYWdlIHwgUHVycG9zZSB8IEtleSBGdW5jdGlvbnMgfA0KfC0tLS0tLS0tLXwtLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfA0KfCBgY2FyZXRgIHwgTWFjaGluZSBsZWFybmluZyB8IGB0cmFpbigpYCwgYHByZWRpY3QoKWAsIGBjb25mdXNpb25NYXRyaXgoKWAgfA0KfCBgcmFuZG9tRm9yZXN0YCB8IFJhbmRvbSBmb3Jlc3RzIHwgYHJhbmRvbUZvcmVzdCgpYCB8DQp8IGBnbG1uZXRgIHwgUmVndWxhcml6ZWQgcmVncmVzc2lvbiB8IGBnbG1uZXQoKWAsIGBjdi5nbG1uZXQoKWAgfA0KfCBgZm9yZWNhc3RgIHwgVGltZSBzZXJpZXMgZm9yZWNhc3RpbmcgfCBgYXV0by5hcmltYSgpYCwgYGV0cygpYCwgYGZvcmVjYXN0KClgIHwNCg0KIyMgMTAuNCBCaWcgRGF0YQ0KDQp8IFBhY2thZ2UgfCBQdXJwb3NlIHwgS2V5IEZ1bmN0aW9ucyB8DQp8LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS18DQp8IGBkYXRhLnRhYmxlYCB8IEZhc3Qgb3BlcmF0aW9ucyB8IEFsbCBvcGVyYXRpb25zIHwNCnwgYGFycm93YCB8IExhcmdlIGZpbGVzIHwgYHJlYWRfcGFycXVldCgpYCwgYG9wZW5fZGF0YXNldCgpYCB8DQp8IGBzcGFya2x5cmAgfCBTcGFyayBpbnRlcmZhY2UgfCBgc3BhcmtfY29ubmVjdCgpYCwgYHNwYXJrX3JlYWRfKigpYCB8DQp8IGBkaXNrLmZyYW1lYCB8IERpc2stYmFzZWQgb3BlcmF0aW9ucyB8IGBjc3ZfdG9fZGlzay5mcmFtZSgpYCB8DQoNCi0tLQ0KDQojIDExLiBBZGRpdGlvbmFsIFJlc291cmNlcw0KDQojIyAxMS4xIEVzc2VudGlhbCBCb29rcw0KDQoxLiAqKiJSIGZvciBEYXRhIFNjaWVuY2UiKiogYnkgSGFkbGV5IFdpY2toYW0gJiBHYXJyZXR0IEdyb2xlbXVuZA0KICAgLSBGcmVlIG9ubGluZTogaHR0cHM6Ly9yNGRzLmhhZC5jby5uei8NCiAgIC0gQmVzdCBpbnRyb2R1Y3Rpb24gdG8gdGlkeXZlcnNlDQoNCjIuICoqIkFkdmFuY2VkIFIiKiogYnkgSGFkbGV5IFdpY2toYW0NCiAgIC0gRnJlZSBvbmxpbmU6IGh0dHBzOi8vYWR2LXIuaGFkbGV5Lm56Lw0KICAgLSBEZWVwIGRpdmUgaW50byBSIHByb2dyYW1taW5nDQoNCjMuICoqIlIgR3JhcGhpY3MgQ29va2Jvb2siKiogYnkgV2luc3RvbiBDaGFuZw0KICAgLSBDb21wcmVoZW5zaXZlIGdncGxvdDIgZ3VpZGUNCg0KNC4gKioiR2VvY29tcHV0YXRpb24gd2l0aCBSIioqIGJ5IFJvYmluIExvdmVsYWNlIGV0IGFsLg0KICAgLSBGcmVlIG9ubGluZTogaHR0cHM6Ly9yLmdlb2NvbXB4Lm9yZy8NCiAgIC0gR2Vvc3BhdGlhbCBkYXRhIGluIFINCg0KNS4gKioiRm9yZWNhc3Rpbmc6IFByaW5jaXBsZXMgYW5kIFByYWN0aWNlIioqIGJ5IFJvYiBIeW5kbWFuDQogICAtIEZyZWUgb25saW5lOiBodHRwczovL290ZXh0cy5jb20vZnBwMy8NCiAgIC0gVGltZSBzZXJpZXMgZm9yZWNhc3RpbmcNCg0KIyMgMTEuMiBPbmxpbmUgUmVzb3VyY2VzDQoNCiMjIyBMZWFybmluZyBQbGF0Zm9ybXMNCi0gUlN0dWRpbyBFZHVjYXRpb246IGh0dHBzOi8vZWR1Y2F0aW9uLnJzdHVkaW8uY29tLw0KLSBEYXRhQ2FtcDogaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tLw0KLSBDb3Vyc2VyYSBSIFNwZWNpYWxpemF0aW9ucw0KLSBlZFggUiBjb3Vyc2VzDQoNCiMjIyBSZWZlcmVuY2UgU2l0ZXMNCi0gQ1JBTiBUYXNrIFZpZXdzOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvdmlld3MvDQotIFJTdHVkaW8gQ2hlYXRzaGVldHM6IGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8NCi0gU3RhY2sgT3ZlcmZsb3cgW3JdIHRhZzogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvdGFnZ2VkL3INCi0gUi1ibG9nZ2VyczogaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vDQoNCiMjIyBDb21tdW5pdGllcw0KLSBSU3R1ZGlvIENvbW11bml0eTogaHR0cHM6Ly9jb21tdW5pdHkucnN0dWRpby5jb20vDQotIHIvcnN0YXRzIChSZWRkaXQpOiBodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnN0YXRzLw0KLSAjcnN0YXRzIG9uIFR3aXR0ZXINCg0KIyMgMTEuMyBTdGF5aW5nIFVwZGF0ZWQNCg0KYGBge3Igc3RheV91cGRhdGVkLCBldmFsPUZBTFNFfQ0KIyBTdWJzY3JpYmUgdG8gUiBXZWVrbHkgbmV3c2xldHRlcg0KIyBodHRwczovL3J3ZWVrbHkub3JnLw0KDQojIEZvbGxvdyBSIGRldmVsb3BlcnMgb24gVHdpdHRlcg0KIyBAaGFkbGV5d2lja2hhbSwgQEplbm55QnJ5YW4sIEBXZUFyZVJMYWRpZXMNCg0KIyBBdHRlbmQgY29uZmVyZW5jZXMNCiMgdXNlUiEsIHJzdHVkaW86OmNvbmYsIHNhdFJkYXlzDQoNCiMgSm9pbiBsb2NhbCBSIHVzZXIgZ3JvdXBzDQojIGh0dHBzOi8vd3d3Lm1lZXR1cC5jb20vdG9waWNzL3ItcHJvamVjdC1mb3Itc3RhdGlzdGljYWwtY29tcHV0aW5nLw0KDQojIFJlYWQgUiBKb3VybmFsDQojIGh0dHBzOi8vam91cm5hbC5yLXByb2plY3Qub3JnLw0KYGBgDQoNCi0tLQ0KDQojIDEyLiBQcmFjdGljZSBFeGVyY2lzZXMNCg0KIyMgRXhlcmNpc2UgMTogRGF0YSBNYW5pcHVsYXRpb24NCmBgYHtyIGV4ZXJjaXNlMSwgZXZhbD1GQUxTRX0NCiMgVGFzazogTG9hZCBtdGNhcnMsIGNyZWF0ZSBuZXcgY29sdW1ucywgc3VtbWFyaXplIGJ5IGdyb3Vwcw0KIyAxLiBDYWxjdWxhdGUgbXBnIHBlciBjeWxpbmRlciByYXRpbw0KIyAyLiBDYXRlZ29yaXplIGNhcnMgYXMgImVmZmljaWVudCIgKG1wZyA+IDIwKSBvciAiaW5lZmZpY2llbnQiDQojIDMuIENhbGN1bGF0ZSBtZWFuIGhwIGFuZCBtZWFuIG1wZyBieSBjeWxpbmRlciBhbmQgZWZmaWNpZW5jeSBjYXRlZ29yeQ0KIyA0LiBTb3J0IHJlc3VsdHMgYnkgbWVhbl9ocCBkZXNjZW5kaW5nDQoNCiMgWW91ciBzb2x1dGlvbiBoZXJlDQpgYGANCg0KIyMgRXhlcmNpc2UgMjogVmlzdWFsaXphdGlvbg0KYGBge3IgZXhlcmNpc2UyLCBldmFsPUZBTFNFfQ0KIyBUYXNrOiBDcmVhdGUgYSBjb21wcmVoZW5zaXZlIHZpc3VhbGl6YXRpb24NCiMgMS4gVXNlIG10Y2FycyBkYXRhc2V0DQojIDIuIENyZWF0ZSBzY2F0dGVyIHBsb3Qgb2YgbXBnIHZzIHd0DQojIDMuIENvbG9yIGJ5IG51bWJlciBvZiBjeWxpbmRlcnMNCiMgNC4gQWRkIHNtb290aGluZyBsaW5lDQojIDUuIEZhY2V0IGJ5IHRyYW5zbWlzc2lvbiB0eXBlIChhbSkNCiMgNi4gQXBwbHkgY3VzdG9tIHRoZW1lDQojIDcuIEFkZCBpbmZvcm1hdGl2ZSBsYWJlbHMNCg0KIyBZb3VyIHNvbHV0aW9uIGhlcmUNCmBgYA0KDQojIyBFeGVyY2lzZSAzOiBUaW1lIFNlcmllcw0KYGBge3IgZXhlcmNpc2UzLCBldmFsPUZBTFNFfQ0KIyBUYXNrOiBBbmFseXplIEFpclBhc3NlbmdlcnMgZGF0YXNldA0KIyAxLiBEZWNvbXBvc2UgdGhlIHRpbWUgc2VyaWVzDQojIDIuIENhbGN1bGF0ZSAxMi1tb250aCBtb3ZpbmcgYXZlcmFnZQ0KIyAzLiBQbG90IG9yaWdpbmFsIHZzIHNtb290aGVkIHNlcmllcw0KIyA0LiBGb3JlY2FzdCAyNCBtb250aHMgYWhlYWQNCiMgNS4gVmlzdWFsaXplIGZvcmVjYXN0IHdpdGggY29uZmlkZW5jZSBpbnRlcnZhbHMNCg0KIyBZb3VyIHNvbHV0aW9uIGhlcmUNCmBgYA0KDQojIyBFeGVyY2lzZSA0OiBGdW5jdGlvbnMNCmBgYHtyIGV4ZXJjaXNlNCwgZXZhbD1GQUxTRX0NCiMgVGFzazogV3JpdGUgYSBmbGV4aWJsZSBzdW1tYXJ5IGZ1bmN0aW9uDQojIENyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQ6DQojIDEuIFRha2VzIGEgZGF0YSBmcmFtZSBhbmQgY29sdW1uIG5hbWUNCiMgMi4gUmV0dXJucyBtZWFuLCBtZWRpYW4sIHNkLCBtaW4sIG1heCwgYW5kIG51bWJlciBvZiBOQXMNCiMgMy4gSGFuZGxlcyBub24tbnVtZXJpYyBjb2x1bW5zIGdyYWNlZnVsbHkNCiMgNC4gT3B0aW9uYWxseSByZW1vdmVzIG91dGxpZXJzIGJlZm9yZSBjYWxjdWxhdGlvbg0KDQojIFlvdXIgc29sdXRpb24gaGVyZQ0KYGBgDQoNCi0tLQ0KDQojIEFwcGVuZGl4OiBTZXNzaW9uIEluZm9ybWF0aW9uDQoNCmBgYHtyIHNlc3Npb25faW5mb30NCiMgU3lzdGVtIGluZm9ybWF0aW9uDQpzZXNzaW9uSW5mbygpDQoNCiMgUGFja2FnZSB2ZXJzaW9ucw0KaW5zdGFsbGVkX3BhY2thZ2VzIDwtIGluc3RhbGxlZC5wYWNrYWdlcygpWywgYygiUGFja2FnZSIsICJWZXJzaW9uIildDQprZXlfcGFja2FnZXMgPC0gYygiZHBseXIiLCAiZ2dwbG90MiIsICJ0aWR5ciIsICJzZiIsICJ0ZXJyYSIsIA0KICAgICAgICAgICAgICAgICAgInNoaW55IiwgImRhdGEudGFibGUiLCAibHVicmlkYXRlIiwgImZvcmVjYXN0IikNCmluc3RhbGxlZF9wYWNrYWdlc1tpbnN0YWxsZWRfcGFja2FnZXNbLCAiUGFja2FnZSJdICVpbiUga2V5X3BhY2thZ2VzLCBdDQpgYGANCg0KLS0tDQoNCiMgUXVpY2sgUmVmZXJlbmNlIENhcmQNCg0KIyMgTW9zdCBVc2VkIEZ1bmN0aW9ucw0KDQpgYGB7ciBxdWlja19yZWYsIGV2YWw9RkFMU0V9DQojIERhdGEgSW1wb3J0L0V4cG9ydA0KcmVhZF9jc3YoKSAgICAgICAgIyBJbXBvcnQgQ1NWDQp3cml0ZV9jc3YoKSAgICAgICAjIEV4cG9ydCBDU1YNCnJlYWRSRFMoKSAgICAgICAgICMgSW1wb3J0IFJEUw0Kc2F2ZVJEUygpICAgICAgICAgIyBFeHBvcnQgUkRTDQoNCiMgRGF0YSBNYW5pcHVsYXRpb24NCnNlbGVjdCgpICAgICAgICAgICMgU2VsZWN0IGNvbHVtbnMNCmZpbHRlcigpICAgICAgICAgICMgRmlsdGVyIHJvd3MNCm11dGF0ZSgpICAgICAgICAgICMgQ3JlYXRlL21vZGlmeSBjb2x1bW5zDQpzdW1tYXJpc2UoKSAgICAgICAjIEFnZ3JlZ2F0ZQ0KZ3JvdXBfYnkoKSAgICAgICAgIyBHcm91cCBkYXRhDQphcnJhbmdlKCkgICAgICAgICAjIFNvcnQgcm93cw0KbGVmdF9qb2luKCkgICAgICAgIyBKb2luIGRhdGENCg0KIyBEYXRhIENsZWFuaW5nDQpuYS5vbWl0KCkgICAgICAgICAjIFJlbW92ZSBOQXMNCnJlcGxhY2VfbmEoKSAgICAgICMgUmVwbGFjZSBOQXMNCmRpc3RpbmN0KCkgICAgICAgICMgUmVtb3ZlIGR1cGxpY2F0ZXMNCnN0cl90cmltKCkgICAgICAgICMgVHJpbSB3aGl0ZXNwYWNlDQoNCiMgVmlzdWFsaXphdGlvbg0KZ2dwbG90KCkgICAgICAgICAgIyBJbml0aWFsaXplIHBsb3QNCmdlb21fcG9pbnQoKSAgICAgICMgU2NhdHRlciBwbG90DQpnZW9tX2xpbmUoKSAgICAgICAjIExpbmUgcGxvdA0KZ2VvbV9iYXIoKSAgICAgICAgIyBCYXIgcGxvdA0KZmFjZXRfd3JhcCgpICAgICAgIyBGYWNldGluZw0KZ2dzYXZlKCkgICAgICAgICAgIyBTYXZlIHBsb3QNCg0KIyBTdGF0aXN0aWNzDQptZWFuKCkgICAgICAgICAgICAjIE1lYW4NCm1lZGlhbigpICAgICAgICAgICMgTWVkaWFuDQpzZCgpICAgICAgICAgICAgICAjIFN0YW5kYXJkIGRldmlhdGlvbg0KY29yKCkgICAgICAgICAgICAgIyBDb3JyZWxhdGlvbg0KbG0oKSAgICAgICAgICAgICAgIyBMaW5lYXIgbW9kZWwNCnN1bW1hcnkoKSAgICAgICAgICMgU3VtbWFyeSBzdGF0aXN0aWNzDQoNCiMgVGltZSBTZXJpZXMNCnRzKCkgICAgICAgICAgICAgICMgQ3JlYXRlIHRpbWUgc2VyaWVzDQpkZWNvbXBvc2UoKSAgICAgICAjIERlY29tcG9zZQ0KbGFnKCkgICAgICAgICAgICAgIyBMYWcgdmFsdWVzDQpkaWZmKCkgICAgICAgICAgICAjIERpZmZlcmVuY2UNCg0KIyBHZW9zcGF0aWFsDQpzdF9yZWFkKCkgICAgICAgICAjIFJlYWQgc3BhdGlhbCBkYXRhDQpzdF90cmFuc2Zvcm0oKSAgICAjIFRyYW5zZm9ybSBDUlMNCnN0X2J1ZmZlcigpICAgICAgICMgQnVmZmVyDQpzdF9pbnRlcnNlY3Rpb24oKSAjIEludGVyc2VjdGlvbg0KYGBgDQoNCi0tLQ0KDQoqKlRoaXMgbWF0ZXJpYWwgaXMgcGFydCBvZiB0aGUgdHJhaW5pbmcgcHJvZ3JhbSBieSBUaGUgTmF0aW9uYWwgQ2VudHJlIGZvciBSZXNlYXJjaCBNZXRob2RzIMKpIFtOQ1JNXShodHRwczovL3d3dy5uY3JtLmFjLnVrL2Fib3V0LykgYXV0aG9yZWQgYnkgW0Ry4oCvU29tbmF0aOKAr0NoYXVkaHVyaV0oaHR0cHM6Ly93d3cuc291dGhhbXB0b24uYWMudWsvcGVvcGxlLzY1Y3RxOC9kb2N0b3Itc29tbmF0aC1jaGF1ZGh1cmkpIChVbml2ZXJzaXR5IG9mIFNvdXRoYW1wdG9uKS4gQ29udGVudCBpcyB1bmRlciBhIEND4oCvQlnigJFzdHlsZSBwZXJtaXNzaXZlIGxpY2Vuc2UgYW5kIGNhbiBiZSBmcmVlbHkgdXNlZCBmb3IgZWR1Y2F0aW9uYWwgcHVycG9zZXMgd2l0aCBwcm9wZXIgYXR0cmlidXRpb24uKio=